<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[SysAdmin Journal]]></title><description><![CDATA[A practical blog sharing real-world challenges, solutions, and insights from the daily life of an IT Systems Administrator.]]></description><link>https://adminjournal.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!TdSv!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5370a8c8-b0a2-410b-a666-a058413b87cd_1280x1280.png</url><title>SysAdmin Journal</title><link>https://adminjournal.substack.com</link></image><generator>Substack</generator><lastBuildDate>Mon, 06 Apr 2026 07:41:05 GMT</lastBuildDate><atom:link href="https://adminjournal.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Драган Вучановић]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[adminjournal@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[adminjournal@substack.com]]></itunes:email><itunes:name><![CDATA[Драган Вучановић]]></itunes:name></itunes:owner><itunes:author><![CDATA[Драган Вучановић]]></itunes:author><googleplay:owner><![CDATA[adminjournal@substack.com]]></googleplay:owner><googleplay:email><![CDATA[adminjournal@substack.com]]></googleplay:email><googleplay:author><![CDATA[Драган Вучановић]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Building a Kubernetes Observability Stack with Prometheus, Loki, and Grafana Alloy]]></title><description><![CDATA[Recently, I embarked on a journey to build a complete observability pipeline from scratch to learn the nuances of the Grafana LGTM stack. In this post, I&#8217;ll break down how I configured Prometheus for metrics, Loki for logs, and the new Grafana Alloy as the ultimate telemetry collector.This was Proof of concept project, so i tested in locally, using Rancher Desktop.]]></description><link>https://adminjournal.substack.com/p/building-a-kubernetes-observability</link><guid isPermaLink="false">https://adminjournal.substack.com/p/building-a-kubernetes-observability</guid><dc:creator><![CDATA[Драган Вучановић]]></dc:creator><pubDate>Thu, 12 Mar 2026 09:37:31 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!UuQl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf675ab7-b82d-49ca-88ea-b726df5113b0_851x570.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UuQl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf675ab7-b82d-49ca-88ea-b726df5113b0_851x570.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UuQl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf675ab7-b82d-49ca-88ea-b726df5113b0_851x570.png 424w, https://substackcdn.com/image/fetch/$s_!UuQl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf675ab7-b82d-49ca-88ea-b726df5113b0_851x570.png 848w, https://substackcdn.com/image/fetch/$s_!UuQl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf675ab7-b82d-49ca-88ea-b726df5113b0_851x570.png 1272w, https://substackcdn.com/image/fetch/$s_!UuQl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf675ab7-b82d-49ca-88ea-b726df5113b0_851x570.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UuQl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf675ab7-b82d-49ca-88ea-b726df5113b0_851x570.png" width="851" height="570" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bf675ab7-b82d-49ca-88ea-b726df5113b0_851x570.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:570,&quot;width&quot;:851,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:273412,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/190705223?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf675ab7-b82d-49ca-88ea-b726df5113b0_851x570.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!UuQl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf675ab7-b82d-49ca-88ea-b726df5113b0_851x570.png 424w, https://substackcdn.com/image/fetch/$s_!UuQl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf675ab7-b82d-49ca-88ea-b726df5113b0_851x570.png 848w, https://substackcdn.com/image/fetch/$s_!UuQl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf675ab7-b82d-49ca-88ea-b726df5113b0_851x570.png 1272w, https://substackcdn.com/image/fetch/$s_!UuQl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf675ab7-b82d-49ca-88ea-b726df5113b0_851x570.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Recently, I embarked on a journey to build a complete observability pipeline from scratch to learn the nuances of the <strong>Grafana LGTM stack</strong>. In this post, I&#8217;ll break down how I configured Prometheus for metrics, Loki for logs, and the new <strong>Grafana Alloy</strong> as the ultimate telemetry collector.This was Proof of concept project, so i tested in locally, using Rancher Desktop.</p><p>You can find the full source code and configuration files for this project in my <a href="https://github.com/dragan1979/prometheus">GitHub repository</a>.</p><div><hr></div><h2>The Architecture</h2><p>The goal was to move away from legacy configurations and toward a modern, &#8220;flow-based&#8221; pipeline. Here is the setup:</p><ul><li><p><strong>Metrics:</strong> Using the <code>kube-prometheus-stack</code> to collect node and container metrics.</p></li><li><p><strong>Logs:</strong> Using <strong>Grafana Alloy</strong> (the successor to the Grafana Agent) to scrape logs directly from the Kubernetes API.</p></li><li><p><strong>Alerting:</strong> A sophisticated <strong>Alertmanager</strong> tree that routes notifications to Slack based on specific team labels.</p></li></ul><div><hr></div><h2>Metrics and Smart Alerting</h2><p>One of the biggest hurdles in monitoring is &#8220;Alert Fatigue.&#8221; To solve this, I implemented a label-based routing strategy.</p><p>By adding a <code>team</code> label to my <code>PrometheusRule</code> manifests, I can ensure that a database memory spike goes to the <strong>DBA Slack channel</strong>, while a CoreDNS failure goes to the <strong>Infrastructure channel</strong>, and Fronted app related alerts goes to <strong>alerts fronted</strong> slack channel.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;yaml&quot;,&quot;nodeId&quot;:&quot;d645614b-f55b-4f6c-9775-f0a23581d052&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-yaml"># Example of a team-specific alert
- alert: SQLPodMemoryUsage
  expr: (container_memory_working_set_bytes{container="mssql"} / kube_pod_container_resource_limits{resource="memory"}) * 100 &gt; 80
  labels:
    severity: critical
    team: database  # This label determines the Slack destination</code></pre></div><h2>Grafana Alloy</h2><p>As of March 2, 2026, Promtail has officially reached its End-of-Life (EOL).While the grafana/promtail chart might still exist in the repository, it is no longer receiving security patches or updates. Grafana has replaced it with a new, unified agent called Grafana Alloy.Alloy is the successor to Promtail. It does everything Promtail did but is faster, uses less memory, and can handle metrics and traces in the same pipeline.Unlike Promtail,Alloy can automatically discover pod log paths. Alloy uses a &#8220;Flow&#8221; configuration. I configured it to:</p><ol><li><p><strong>Discover</strong> pods in specific namespaces.</p></li><li><p><strong>Filter</strong> for specific application containers (<code>mvc</code> and <code>mssql</code>).</p></li><li><p><strong>Process</strong> logs to drop noisy SQL error paths before they even hit storage.</p></li></ol><p>This keeps the storage costs in Loki low and the signal-to-noise ratio high.</p><h2>Alertmanager</h2><p>The final piece of the puzzle was the <code>AlertmanagerConfig</code>. I set up a hierarchy where every alert is caught by a &#8220;Global SRE&#8221; receiver, but specific sub-routes handle the specialized teams.</p><p>Using <code>continue: true</code> in the routing logic allows an alert to be sent to both a general &#8220;All Systems&#8221; channel and a specific team channel simultaneously&#8212;ensuring no critical issue is ever missed.</p><p></p><p>The <code>prometheus-overrides.yaml</code> file is the &#8220;instruction manual&#8221; for Helm deployment. When we install a complex stack like <code>kube-prometheus-stack</code>, it comes with hundreds of default settings. The override file allows us to change only the specific parts we need without modifying the original chart.</p><h3>Connecting the &#8220;Operator&#8221; to Rules</h3><p>The Prometheus Operator acts like a watchman. It doesn&#8217;t just load every file it finds; it looks for specific labels. In <code>prometheus-overrides.yaml</code>, we define a <strong>Rule Selector</strong>.</p><ul><li><p><strong>I </strong>set it to look for <code>prometheus: prometheus</code>.</p></li><li><p>This ensures that when we apply <code>cluster-alerts.yaml</code> or <code>microservices-alerts.yaml</code> (which both have that label), the Operator &#8220;sees&#8221; them and injects them into the Prometheus engine.</p></li></ul><h3>Configuring Alertmanager Routing</h3><p>By default, Alertmanager might not know how to handle specific Kubernetes Custom Resources (CRDs).</p><ul><li><p><strong>I </strong>configured the <code>alertmanagerConfigMatcherStrategy</code> to <code>type: None</code>.</p></li><li><p>This allows Alertmanager to treat labels from <code>AlertmanagerConfig</code> (like the <code>team</code> labels for Slack) as global labels. Without this override, Alertmanager would ignore specific routing instructions for different Slack channels.</p></li></ul><h3>Enabling/Disabling Default Metrics</h3><p>The standard Prometheus stack tries to monitor everything (CoreDNS, etcd, KubeProxy, etc.). However, in environments like <strong>Rancher Desktop</strong>, some of these components aren&#8217;t accessible.</p><ul><li><p>Under <code>defaultRules</code>, i set <code>etcd: false</code> and <code>kubeScheduler: false</code>.</p></li><li><p>This prevents dashboard from being filled with &#8220;Red&#8221; failing alerts for services that don&#8217;t actually exist in local setup.</p></li></ul><h3>Infrastructure &amp; Persistence</h3><p>Prometheus is a database. If the Pod restarts and we haven&#8217;t configured storage, we lose all historical graphs.</p><ul><li><p><strong> </strong>A <code>volumeClaimTemplate </code> is defined using the <code>local-path</code> storage class with a <code>2Gi</code> limit.</p></li><li><p>This ensures that metrics survive a computer reboot or a pod crash by saving the data to the disk.</p></li></ul><p></p><h3>SQL deployment monitoring</h3><p>The metrics for MS SQL database didn&#8217;t come directly from the SQL engine; instead, they were collected through a <strong>Sidecar or Exporter pattern</strong>.</p><ul><li><p><strong>The Exporter is </strong>A specialized tool (like the <code>sql_exporter</code> or <code>mssql-exporter</code>) runs alongside the database. It connects to SQL Server, runs system queries (like <code>SELECT * FROM sys.dm_os_process_memory</code>), and converts the results into a format Prometheus can read (HTTP/text).</p></li><li><p>Prometheus is configured to &#8220;scrape&#8221; (visit) the exporter&#8217;s endpoint every few seconds.</p></li><li><p>In <code>microservices-alerts.yaml</code>, i defined a <code>PrometheusRule</code>. Prometheus takes the raw bytes collected from the exporter and runs the math written in the <code>expr</code> (expression) field:</p></li></ul><h3>Fronted deployment monitoring</h3><p>Monitoring the &#8220;Health&#8221; of a URL (like checking if a website is up) is called <strong>Probing</strong> or <strong>Synthetic Monitoring</strong>. This was handled by the <strong>Prometheus Blackbox Exporter</strong>.</p><ul><li><p>Unlike standard metrics where a pod <em>tells</em> you its health, the Blackbox Exporter acts like an outside user. It tries to &#8220;hit&#8221; the URL you specify.</p></li><li><p>It sends an HTTP GET request to the frontend service. If the service responds with a <code>200 OK</code> status code, the probe returns a <code>1</code> (Success). If the site is down or returns a <code>500 Error</code>, it returns a <code>0</code> (Failure).</p></li><li><p>In your <code>microservices-alerts.yaml</code>, we have an alert named <code>MvcFrontendDown</code>. It looks specifically at the result of that probe:</p></li></ul><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;8388581a-0db4-435d-af30-bdb6bb35524a&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">- alert: MvcFrontendDown
  expr: probe_success{job="mvc-frontend-check"} == 0
  for: 2m</code></pre></div><p></p><p>To find out what labels prometheus/alertmanager expects, run this command to find out:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;59600f4e-7633-4e07-9191-bd42fbf980a8&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">kubectl get prometheus -n monitoring -o jsonpath='{.items[0].spec.ruleSelector}'                                                       
# output
{"matchLabels":{"prometheus":"prometheus"}}    </code></pre></div><p>It is telling the Operator: &#8220;I will only load rules that have the label prometheus: prometheus</p><p>For blackbox exporter (used to monitor frontend app URL) and services</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;ff933fa1-ab3d-4429-82cc-1605b1830e9b&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">kubectl get prometheus -n monitoring -o jsonpath='{.items[0].spec.serviceMonitorSelector}'
{"matchLabels":{"release":"prometheus"}}</code></pre></div><p>Check if prometheus/alert manager rules are loaded</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;2bd751f1-351c-4b2c-b09b-0dca4e661c6d&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext"># restart prometheus/alert manager deployments after config changes
kubectl rollout restart statefulset alertmanager-prometheus-kube-prometheus-alertmanager -n monitoring
kubectl rollout restart statefulset prometheus-prometheus-kube-prometheus-prometheus -n monitoring
kubectl logs -n monitoring -l app.kubernetes.io/name=prometheus --tail=50 | grep -i "rule"
kubectl logs -n monitoring -l app.kubernetes.io/name=alertmanager --tail=50</code></pre></div><p>Check if Aloy rules are loaded:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;1750a156-9ed5-4a4c-811a-f559a7667561&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">kubectl logs -n monitoring -l app.kubernetes.io/name=alloy --tail=100
# restart alloy after config changes
kubectl rollout restart ds alloy -n monitoring </code></pre></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/building-a-kubernetes-observability?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/building-a-kubernetes-observability?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/building-a-kubernetes-observability/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/building-a-kubernetes-observability/comments"><span>Leave a comment</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[CI/CD Blueprint with Jenkins Shared Libraries and Kubernetes]]></title><description><![CDATA[I built this project as a comprehensive learning journey to master the intersection of Node.js development and modern Cloud Native operations.]]></description><link>https://adminjournal.substack.com/p/cicd-blueprint-with-jenkins-shared</link><guid isPermaLink="false">https://adminjournal.substack.com/p/cicd-blueprint-with-jenkins-shared</guid><dc:creator><![CDATA[Драган Вучановић]]></dc:creator><pubDate>Wed, 11 Feb 2026 10:53:18 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!pUPb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71bfdedc-6623-4c2b-a810-9f5a2767e852_680x621.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pUPb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71bfdedc-6623-4c2b-a810-9f5a2767e852_680x621.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pUPb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71bfdedc-6623-4c2b-a810-9f5a2767e852_680x621.png 424w, https://substackcdn.com/image/fetch/$s_!pUPb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71bfdedc-6623-4c2b-a810-9f5a2767e852_680x621.png 848w, https://substackcdn.com/image/fetch/$s_!pUPb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71bfdedc-6623-4c2b-a810-9f5a2767e852_680x621.png 1272w, https://substackcdn.com/image/fetch/$s_!pUPb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71bfdedc-6623-4c2b-a810-9f5a2767e852_680x621.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pUPb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71bfdedc-6623-4c2b-a810-9f5a2767e852_680x621.png" width="680" height="621" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/71bfdedc-6623-4c2b-a810-9f5a2767e852_680x621.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:621,&quot;width&quot;:680,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:556642,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/187615234?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71bfdedc-6623-4c2b-a810-9f5a2767e852_680x621.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pUPb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71bfdedc-6623-4c2b-a810-9f5a2767e852_680x621.png 424w, https://substackcdn.com/image/fetch/$s_!pUPb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71bfdedc-6623-4c2b-a810-9f5a2767e852_680x621.png 848w, https://substackcdn.com/image/fetch/$s_!pUPb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71bfdedc-6623-4c2b-a810-9f5a2767e852_680x621.png 1272w, https://substackcdn.com/image/fetch/$s_!pUPb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71bfdedc-6623-4c2b-a810-9f5a2767e852_680x621.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I built this project as a comprehensive learning journey to master the intersection of Node.js development and modern Cloud Native operations. My goal was to move beyond basic tutorials and implement a real-world, production-ready environment using the 'Everything-as-Code' philosophy."</p><p>In this post, I&#8217;ll walk through a comprehensive project that bridges the gap between development and operations. We&#8217;ll look at a <strong>Node.js</strong> microservice backed by <strong>MongoDB</strong>, deployed via <strong>Helm</strong>, and automated through a custom <strong>Jenkins Shared Library</strong> that integrates with <strong>AWS Parameter Store</strong>.Check out the <a href="https://github.com/dragan1979/jenkins-eks">full source code</a> on GitHub.</p><p>The project is built on the philosophy of <strong>Everything-as-Code</strong>.</p><ol><li><p><strong>Application Layer:</strong> A Node.js API.</p></li><li><p><strong>Orchestration:</strong> Kubernetes managed via Helm charts.</p></li><li><p><strong>Secrets Management:</strong> External Secrets Operator (ESO) syncing from AWS Parameter Store.</p></li><li><p><strong>CI/CD Pipeline:</strong> A modular Jenkins Shared Library to avoid code duplication across multiple repositories.</p></li></ol><h3>Pipeline breakdown</h3><p>When code is pushed to a branch that is <strong>not master</strong> and has <strong>no open Pull Request</strong>, only the baseline quality checks run. This is designed to give developers fast feedback without wasting registry space or deployment time.</p><ul><li><p><strong>Stages that run:</strong></p><ul><li><p><strong>Tests &amp; Coverage:</strong> Spins up the temporary MongoDB, runs <code>yarn coverage</code>, and publishes the HTML report.</p></li><li><p><strong>Analysis &amp; Lint:</strong> Runs <code>yarn lint</code> and the <strong>SonarCloud</strong> scan. It will wait for the Quality Gate to pass.</p></li></ul><p></p><p>Everything else is skipped (Nexus, Docker, ECR, EKS).</p></li></ul><p>Once we open a Pull Request (PR), Jenkins identifies this as a <code>changeRequest()</code>. The pipeline now adds the &#8220;Publishing&#8221; and &#8220;Validation&#8221; steps.</p><ul><li><p><strong>Stages that run:</strong></p><ul><li><p><strong>Tests &amp; Coverage</strong> &amp; <strong>Analysis &amp; Lint</strong> (Always run).</p></li><li><p><strong>Publish to Nexus:</strong> NPM package is published to private Nexus repository.</p></li><li><p><strong>Build Docker Image:</strong> A Docker image is built using the Jenkins Build Number as a tag.</p></li><li><p><strong>Image Analysis:</strong> The image is scanned for vulnerabilities (Trivy/Clair/etc.) with a focus on <code>CRITICAL</code> issues.</p></li></ul></li><li><p><strong>Post-Action:</strong></p><ul><li><p>Because <code>env.CHANGE_ID</code> is now active, the <code>post</code> block executes the <strong>GitHub PR Comment</strong> logic. It collects the test results and coverage % and posts them directly onto your PR conversation so reviewers can see the stats without leaving GitHub.</p></li></ul></li></ul><p>After the PR is approved and merged, the pipeline runs on <code>master</code>. This is the only time the actual deployment takes place.</p><ul><li><p><strong>Stages that run:</strong></p><ul><li><p>All <strong>CI stages</strong> (Tests, Lint, Sonar).</p></li><li><p>All <strong>PR stages</strong> (Nexus, Docker Build, Image Scan).</p></li><li><p><strong>Approval Gate:</strong> The pipeline <strong>pauses</strong>. It waits up to 1 hour for a human to click &#8220;Deploy&#8221; in the Jenkins UI.</p></li><li><p><strong>Push to ECR:</strong> Authenticates with AWS and pushes the <code>latest</code> and <code>BUILD_NUMBER</code> tagged images to Amazon ECR.</p></li><li><p><strong>Deploy to EKS:</strong> Runs <code>helm upgrade --install</code> to update the Kubernetes cluster with the new image.</p></li></ul></li><li><p><strong>Post-Action:</strong> * Since it&#8217;s no longer a PR (<code>CHANGE_ID</code> is null), it skips the GitHub comment and simply prints &#8220;Pipeline completed successfully!&#8221;</p></li></ul><p>Instead of static YAML files, this project uses <strong>Helm</strong> to parameterize the environment. This allows us to use the same chart for Dev, Staging, and Production by simply swapping <code>values.yaml</code>.</p><p>We&#8217;ve implemented an HPA (<code>app-hpa.yaml</code>) that monitors CPU utilization. If the load spikes, Kubernetes automatically scales our Node.js replicas up to 10.</p><p>The deployment uses a <code>RollingUpdate</code> strategy, ensuring that at least two pods are always healthy while a new version is being rolled out.</p><p>A Headless Service handles internal communication for MongoDB, while a LoadBalancer exposes the Node.js API to the world.</p><p>Hardcoding secrets is a not a good practice in DevOps. This project utilizes the <strong>External Secrets Operator</strong>.</p><p>YAML</p><pre><code><code># From secrets.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
spec:
  secretStoreRef:
    name: aws-parameter-store
  data:
  - secretKey: password
    remoteRef:
      key: /my-aks-cluster/mongodb/root-password
</code></code></pre><p>By using this pattern, our Kubernetes secrets are automatically synced from <strong>AWS SSM</strong>, keeping sensitive data out of our Git history and ensuring that rotation is handled at the source.</p><h2>Jenkins Shared Libraries</h2><p>The standout feature of this setup is the <strong>Jenkins Shared Library</strong>. Instead of writing 100-line Jenkinsfiles for every service, we define the logic once in a centralized repository.</p><h3>Why Shared Libraries?</h3><ul><li><p><strong>Standardization:</strong> Every microservice follows the same build, test, and deploy logic.</p></li><li><p><strong>Easier Maintenance:</strong> Updating a deployment step in the library instantly updates all connected pipelines.</p></li><li><p><strong>Readability:</strong> The application-level <code>Jenkinsfile</code> becomes a simple configuration call.</p></li></ul><p>Shared libraries code is also <a href="https://github.com/dragan1979/jenkins-shared-library">on GitHub</a></p><p>To ensure our cluster doesn&#8217;t run out of memory, we define strict resource limits:</p><p>YAML</p><pre><code><code>nodesApp:
  requests:
    cpu: "50m"
    memory: "64Mi"
  limits:
    cpu: "200m"
    memory: "128Mi"
</code></code></pre><p>We dynamically construct the MongoDB URL to support different namespaces and service names:</p><p> </p><pre><code><code>data:
  MONGODB_URL: {{ printf "mongodb://%s-mongodb-0.%s-mongodb:27017/%s" ... }}
</code></code></pre><p>By implementing this stack, we achieve:</p><ul><li><p><strong>Scalability:</strong> The HPA ensures we only pay for the compute we use.</p></li><li><p><strong>Reliability:</strong> Readiness and Liveness probes ensure traffic only hits healthy pods.</p></li><li><p><strong>Portability:</strong> The Helm chart can be deployed to EKS, GKE, or AKS with minimal changes.</p></li></ul><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/cicd-blueprint-with-jenkins-shared?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/cicd-blueprint-with-jenkins-shared?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/cicd-blueprint-with-jenkins-shared/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/cicd-blueprint-with-jenkins-shared/comments"><span>Leave a comment</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[GitOps: Automating EKS with Terraform and Jenkins]]></title><description><![CDATA[I created a small project as part of my journey into learning DevOps,and the code is available on GitHub.]]></description><link>https://adminjournal.substack.com/p/gitops-automating-eks-with-terraform</link><guid isPermaLink="false">https://adminjournal.substack.com/p/gitops-automating-eks-with-terraform</guid><dc:creator><![CDATA[Драган Вучановић]]></dc:creator><pubDate>Fri, 06 Feb 2026 08:44:10 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!1mXs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb493deac-03e9-4378-a46e-5b9522d6d929_775x599.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1mXs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb493deac-03e9-4378-a46e-5b9522d6d929_775x599.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1mXs!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb493deac-03e9-4378-a46e-5b9522d6d929_775x599.png 424w, https://substackcdn.com/image/fetch/$s_!1mXs!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb493deac-03e9-4378-a46e-5b9522d6d929_775x599.png 848w, https://substackcdn.com/image/fetch/$s_!1mXs!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb493deac-03e9-4378-a46e-5b9522d6d929_775x599.png 1272w, https://substackcdn.com/image/fetch/$s_!1mXs!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb493deac-03e9-4378-a46e-5b9522d6d929_775x599.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1mXs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb493deac-03e9-4378-a46e-5b9522d6d929_775x599.png" width="775" height="599" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b493deac-03e9-4378-a46e-5b9522d6d929_775x599.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:599,&quot;width&quot;:775,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:530794,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/187065798?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb493deac-03e9-4378-a46e-5b9522d6d929_775x599.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1mXs!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb493deac-03e9-4378-a46e-5b9522d6d929_775x599.png 424w, https://substackcdn.com/image/fetch/$s_!1mXs!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb493deac-03e9-4378-a46e-5b9522d6d929_775x599.png 848w, https://substackcdn.com/image/fetch/$s_!1mXs!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb493deac-03e9-4378-a46e-5b9522d6d929_775x599.png 1272w, https://substackcdn.com/image/fetch/$s_!1mXs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb493deac-03e9-4378-a46e-5b9522d6d929_775x599.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I created a small project as part of my journey into learning DevOps,and t<a href="https://github.com/dragan1979/aws-eks">he code is available on GitHub</a>.</p><p>Here is a deep dive into the architecture and the automation logic behind it.</p><div><hr></div><h2>1. The Root Orchestrator (<code>main.tf</code>)</h2><p>The root <code>main.tf</code> is the &#8220;brain&#8221; of the project. Instead of just creating resources, it manages the lifecycle and dependencies between the different layers of the stack.the <strong>root main.tf</strong> doesn't just deploy a cluster; it bootstraps an entire environment. By using the Helm provider directly in the root, we have created a tight coupling between the EKS cluster's health and the application's availability.</p><h4><strong>1. Bridge Between Infrastructure and App</strong></h4><p>The root file calls <code>module.eks</code> first. Once the cluster is ready, it passes the resulting cluster endpoints and security credentials into the <code>module.addons</code>. This ensures that we never try to install software before the &#8220;hardware&#8221; (the VPC and EKS) exists.</p><h4><strong>2. Automated Secret Management</strong></h4><p>This is where the <strong>MongoDB security</strong> is defined. Inside the root <code>main.tf</code>, we use the <code>random_password</code> resource to generate a 16-character complex password.</p><ul><li><p>The password is never hardcoded.</p></li><li><p>Terraform immediately saves this password into the <strong>AWS SSM Parameter Store</strong> as a <code>SecureString</code>. This allows your developers or other applications to retrieve the password securely via the AWS Console or CLI without ever seeing it in the git logs.</p></li></ul><h4><strong>3. The MongoDB Deployment (Helm)</strong></h4><p>The actual creation of the MongoDB database happens here using the <strong>Helm Provider</strong>.</p><ul><li><p>It configures MongoDB to use the <code>gp3</code> StorageClass (created in the EKS module), ensuring that if a database pod restarts, your data is safe on an AWS EBS volume.</p></li><li><p>It maps the generated random password directly into the Helm chart values.</p></li><li><p>It ensures MongoDB is deployed into a clean, dedicated namespace to keep the cluster organized.</p></li></ul><div><hr></div><h2>2. The EKS Module (<code>module_eks</code>)</h2><p>This is the foundation of the environment. It handles the &#8220;Heavy Lifting&#8221; of AWS networking and compute.</p><ul><li><p>Provisions a dedicated VPC with public subnets, an Internet Gateway, and optimized route tables.</p></li><li><p>Deploys the EKS cluster using <strong>API and ConfigMap authentication mode</strong> for modern access management.</p></li><li><p>Uses <code>t3.medium</code> instances with automated scaling to balance cost and performance.</p></li><li><p>Configures the OIDC provider and IAM roles for service accounts, allowing Kubernetes pods to interact with AWS services securely.</p></li><li><p>Automatically installs the <strong>EBS CSI Driver</strong> and sets up <code>gp3</code> as the default StorageClass.</p></li></ul><div><hr></div><h2>3. The Add-ons Module (<code>module_addons</code>)</h2><p>Once the cluster is up, the Add-ons module &#8220;decorates&#8221; it with necessary services.</p><ul><li><p>This module is the &#8220;Security Vault&#8221; for Kubernetes cluster. Instead managing infrastructure, it focuses on how applications safely consume sensitive data from AWS.</p><p>We are using the new <strong>EKS Pod Identity</strong> feature rather than the older IRSA (OIDC) method.</p><ul><li><p>We<strong> </strong>create a specialized IAM role (<code>eso-role</code>) that trusts the <code>pods.eks.amazonaws.com</code> service.</p></li><li><p>The <code>aws_eks_pod_identity_association</code> creates a direct link between the Kubernetes Service Account in the <code>external-secrets</code> namespace and our AWS IAM role.</p></li></ul><p>The module defines a strict IAM policy (<code>eso_secrets_policy</code>) that grants the cluster permission to reach out and &#8220;read&#8221; from two specific AWS services:</p><ul><li><p><strong>AWS Secrets Manager:</strong> For high-rotation application secrets.</p></li><li><p><strong>AWS SSM Parameter Store:</strong> For configuration and passwords (like MongoDB root password).</p></li></ul><p>We deploy the <strong>External Secrets Operator</strong> via a Helm chart.</p><ul><li><p>ESO acts as a controller that synchronizes secrets from AWS into native Kubernetes Secrets.</p></li><li><p>By setting <code>installCRDs = true</code>, Terraform automatically prepares the cluster to understand custom secret resources.</p></li></ul><p></p></li><li><p>The module concludes with a <code>null_resource</code> that executes a <code>local-exec</code> provisioner.</p><ul><li><p>It applies a <code>ClusterSecretStore</code> manifest using <code>kubectl</code>.</p></li><li><p>This tells the entire cluster: <em>&#8220;If you need a secret from AWS Parameter Store in this region, use this specific provider.&#8221;</em> This allows MongoDB deployment to automatically fetch its password from AWS SSM without you ever having to manually create a secret in Kubernetes.</p></li></ul></li></ul><div><hr></div><h2>4. The CI/CD Pipeline (<code>Jenkinsfile</code>)</h2><p>The pipeline is what turns &#8220;code&#8221; into &#8220;infrastructure.&#8221; </p><ul><li><p>Runs <code>fmt</code> and <code>validate</code> to catch syntax errors before they ever reach AWS.</p></li><li><p>Uses <strong>AquaSec Trivy</strong> to scan the Terraform code for misconfigurations (like open S3 buckets or overly permissive IAM roles).</p></li><li><p>A custom Groovy script extracts the <code>terraform plan</code> and <strong>posts it as a comment on the GitHub Pull Request</strong>. This allows reviewers to see exactly what will change before they hit &#8220;Merge.&#8221;</p></li><li><p>For the production (<code>master</code>) branch, the pipeline pauses. A human must manually click &#8220;Deploy&#8221; to trigger the final <code>apply</code>.</p></li><li><p>Uses <code>tfplan</code> binary files to ensure that the exact plan approved in the PR is the one applied to AWS.</p></li></ul><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/gitops-automating-eks-with-terraform?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/gitops-automating-eks-with-terraform?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/gitops-automating-eks-with-terraform/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/gitops-automating-eks-with-terraform/comments"><span>Leave a comment</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[External Secrets Operator (ESO) in Kubernetes]]></title><description><![CDATA[In modern cloud-native environments, managing sensitive data like database passwords or API keys can be a logistical nightmare.]]></description><link>https://adminjournal.substack.com/p/external-secrets-operator-eso-in</link><guid isPermaLink="false">https://adminjournal.substack.com/p/external-secrets-operator-eso-in</guid><dc:creator><![CDATA[Драган Вучановић]]></dc:creator><pubDate>Tue, 03 Feb 2026 15:44:38 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!t8ZP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36844a3b-6bdc-457a-b629-1349cf86cba0_1012x906.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!t8ZP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36844a3b-6bdc-457a-b629-1349cf86cba0_1012x906.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!t8ZP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36844a3b-6bdc-457a-b629-1349cf86cba0_1012x906.png 424w, https://substackcdn.com/image/fetch/$s_!t8ZP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36844a3b-6bdc-457a-b629-1349cf86cba0_1012x906.png 848w, https://substackcdn.com/image/fetch/$s_!t8ZP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36844a3b-6bdc-457a-b629-1349cf86cba0_1012x906.png 1272w, https://substackcdn.com/image/fetch/$s_!t8ZP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36844a3b-6bdc-457a-b629-1349cf86cba0_1012x906.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!t8ZP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36844a3b-6bdc-457a-b629-1349cf86cba0_1012x906.png" width="1012" height="906" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/36844a3b-6bdc-457a-b629-1349cf86cba0_1012x906.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:906,&quot;width&quot;:1012,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:909689,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/186746707?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36844a3b-6bdc-457a-b629-1349cf86cba0_1012x906.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!t8ZP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36844a3b-6bdc-457a-b629-1349cf86cba0_1012x906.png 424w, https://substackcdn.com/image/fetch/$s_!t8ZP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36844a3b-6bdc-457a-b629-1349cf86cba0_1012x906.png 848w, https://substackcdn.com/image/fetch/$s_!t8ZP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36844a3b-6bdc-457a-b629-1349cf86cba0_1012x906.png 1272w, https://substackcdn.com/image/fetch/$s_!t8ZP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F36844a3b-6bdc-457a-b629-1349cf86cba0_1012x906.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In modern cloud-native environments, managing sensitive data like database passwords or API keys can be a logistical nightmare. While Kubernetes has a native <code>Secret</code> object, it lacks a secure, automated way to pull those secrets from external vaults like <strong>AWS Secrets Manager</strong> or <strong>SSM Parameter Store</strong>.</p><p>This is where the <strong>External Secrets Operator (ESO)</strong> comes in.</p><h3>What is External Secrets Operator (ESO)?</h3><p>The <strong>External Secrets Operator (ESO)</strong> is a Kubernetes operator that integrates external secret management systems into Kubernetes. Instead of manually creating Kubernetes Secrets, you define where the secret lives in  cloud provider (like AWS), and ESO automatically fetches it, synchronizes it, and injects it into cluster as a standard Kubernetes Secret.</p><h4>How it Works:</h4><ol><li><p><strong>Poll &amp; Fetch</strong>: ESO monitors cloud provider (AWS, GCP, Azure, etc.) for changes to specific secrets.</p></li><li><p><strong>Mapping</strong>: It uses a custom resource called a <code>ClusterSecretStore</code> to define <strong>how</strong> to connect to the cloud provider (e.g., using specific AWS regions and IAM roles).</p></li><li><p><strong>Synchronization</strong>: It creates a native Kubernetes <code>Secret</code>. If you update the password in the AWS Console, ESO detects the change and updates the Kubernetes Secret automatically.</p></li></ol><p>This example deployment uses a modular Terraform approach to set up ESO with <strong>EKS Pod Identity</strong>, which is the most secure way to grant permissions to pods without managing long-lived IAM keys.</p><h4>Security First: IAM Roles and Policies</h4><p>To implement the <strong>External Secrets Operator (ESO)</strong> with <strong>EKS Pod Identity</strong>, the configuration is spread across IAM roles, policies, and the Helm deployment.To allow ESO to &#8220;read&#8221; from AWS, we first create an IAM role with a trust policy specifically for EKS Pod Identity.</p><pre><code># IAM policy allowing ESO to read from Secrets Manager and SSM
resource "aws_iam_policy" "eso_secrets_policy" {
  name = "${var.cluster_name}-eso-secrets-policy"
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = ["ssm:GetParameter", "ssm:GetParameters", "ssm:GetParametersByPath"]
        Resource = "arn:aws:ssm:${var.region}:${data.aws_caller_identity.current.account_id}:parameter/*"
      }
    ]
  })
}

# ESO IAM Role using Pod Identity trust policy
resource "aws_iam_role" "eso_role" {
  name = "${var.cluster_name}-eso-role"
  
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Principal = { Service = "pods.eks.amazonaws.com" }
      Action    = ["sts:AssumeRole", "sts:TagSession"]
    }]
  })
}

# Attach the policy to the role
resource "aws_iam_role_policy_attachment" "eso_attach" {
  role       = aws_iam_role.eso_role.name
  policy_arn = aws_iam_policy.eso_secrets_policy.arn
}</code></pre><h3>EKS Pod Identity Association</h3><p>This section links the IAM role to the specific Kubernetes ServiceAccount used by the operator. Note that the <strong>Pod Identity Agent</strong> must be installed as an EKS add-on for this to function.</p><pre><code># The Pod Identity Agent add-on must be active on the cluster
resource "aws_eks_addon" "pod_identity_agent" {
  cluster_name = var.cluster_name
  addon_name   = "eks-pod-identity-agent"
}

# Link the IAM role to the 'external-secrets' ServiceAccount in the 'external-secrets' namespace
resource "aws_eks_pod_identity_association" "eso_association" {
  cluster_name    = var.cluster_name
  namespace       = "external-secrets"
  service_account = "external-secrets"
  role_arn        = aws_iam_role.eso_role.arn
}</code></pre><p>We use the <code>aws_eks_pod_identity_association</code> to link the IAM role we created to the specific <code>external-secrets</code> ServiceAccount in the Kubernetes cluster. This ensures that only the ESO pods have the permission to fetch secrets.The operator itself is deployed using the official Helm chart. We ensure that Custom Resource Definitions (CRDs) are installed so Kubernetes understands the new "ExternalSecret" objects.</p><h3>Helm Deployment and Cluster Configuration</h3><p>This code deploys the operator and configures the <code>ClusterSecretStore</code> to tell ESO to look in the AWS Parameter Store for secrets.</p><p></p><pre><code># Deploy ESO via Helm
resource "helm_release" "external_secrets" {
  name             = "external-secrets"
  repository       = "https://charts.external-secrets.io"
  chart            = "external-secrets"
  namespace        = "external-secrets"
  create_namespace = true
  version          = "0.9.11"

  values = [
    yamlencode({
      installCRDs = true
      serviceAccount = {
        create = true
        name   = "external-secrets"
      }
    })
  ]
  
  depends_on = [aws_eks_pod_identity_association.eso_association]
}

# Apply the ClusterSecretStore manifest using local-exec (PowerShell example)
resource "null_resource" "apply_manifest" {
  depends_on = [helm_release.external_secrets]

  provisioner "local-exec" {
    interpreter = ["PowerShell", "-Command"]
    command = &lt;&lt;EOT
      aws eks update-kubeconfig --region ${var.region} --name ${var.cluster_name}
      
      $manifest = @"
apiVersion: external-secrets.io/v1beta1
kind: ClusterSecretStore
metadata:
  name: aws-parameter-store
spec:
  provider:
    aws:
      service: ParameterStore
      region: ${var.region}
"@
      $manifest | Out-File -FilePath manifest.yaml -Encoding ascii
      kubectl apply -f manifest.yaml
      Remove-Item manifest.yaml
EOT
  }
}</code></pre><p>Finally, we apply a <code>ClusterSecretStore</code> manifest. This is the configuration that tells ESO: <em>&#8220;Whenever you need to find a secret, look in the AWS Parameter Store in this specific region&#8221;</em>.</p><p>While the External Secrets Operator (ESO) has a role to <em>fetch</em> secrets, your application needs its own role to authorize the retrieval of that specific secret data through the ESO mechanism.</p><pre><code># IAM Policy allowing the app to read specific parameters
resource "aws_iam_policy" "node_app_secrets_policy" {
  name        = "${var.cluster_name}-node-app-secrets-policy"
  description = "Allows Node app to read its specific MongoDB password from SSM"

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "ssm:GetParameter"
        ]
        # Restrict specifically to the path used by the app
        Resource = "arn:aws:ssm:${var.region}:${data.aws_caller_identity.current.account_id}:parameter/${var.cluster_name}/mongodb/*"
      }
    ]
  })
}

# IAM Role for the Application
resource "aws_iam_role" "node_app_role" {
  name = "${var.cluster_name}-node-app-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Effect    = "Allow"
      Principal = { Service = "pods.eks.amazonaws.com" }
      Action    = ["sts:AssumeRole", "sts:TagSession"]
    }]
  })
}

# Attach the policy to the application role
resource "aws_iam_role_policy_attachment" "node_app_attach" {
  role       = aws_iam_role.node_app_role.name
  policy_arn = aws_iam_policy.node_app_secrets_policy.arn
}

# Pod Identity Association for the Node App
resource "aws_eks_pod_identity_association" "node_app_association" {
  cluster_name    = var.cluster_name
  namespace       = var.namespace
  service_account = "node-app-sa" # Matches the SA in your deployment
  role_arn        = aws_iam_role.node_app_role.arn
}</code></pre><h3>How to &#8220;Get&#8221; the Secret: The ExternalSecret Manifest</h3><p>Once the IAM roles are ready, we define an <code>ExternalSecret</code> custom resource. This is the bridge that tells ESO: &#8220;Go to this AWS path, find the value, and put it in a Kubernetes Secret named <code>mongodb-credentials</code>.&#8221;</p><pre><code>apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: mongodb-pass-sync
  namespace: default
spec:
  refreshInterval: 1h             # How often to sync from AWS
  secretStoreRef:
    name: aws-parameter-store     # Defined in your ClusterSecretStore
    kind: ClusterSecretStore
  target:
    name: mongodb-credentials     # The name of the K8s Secret to create
    creationPolicy: Owner
  data:
  - secretKey: password           # The key inside the K8s Secret
    remoteRef:
      key: /my-aks-cluster/mongodb/root-password  # The path in AWS SSM</code></pre><p>Finally, we map that synchronized Kubernetes Secret your application's environment variables within deployment manifest (password for Mongo DB).</p><pre><code># Deployment example
spec:
  template:
    spec:
      containers:
      - name: node-app
        env:
        - name: MONGODB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mongodb-credentials
              key: password
        # This password is then used to build your MONGODB_URL
        - name: MONGODB_URL
          value: "mongodb://root:$(MONGODB_PASSWORD)@mongodb.default.svc.cluster.local:27017/node-app-db?authSource=admin&amp;ssl=false&amp;directConnection=true"</code></pre><h4>Summary:</h4><ul><li><p><strong>Terraform</strong> generates a random password and stores it in <strong>AWS SSM Parameter Store</strong>.</p></li><li><p><strong>IAM Roles &amp; Pod Identity</strong> give permission to <strong>ESO</strong> to read from SSM.</p></li><li><p><strong>ExternalSecret</strong> tells ESO which AWS path to watch.</p></li><li><p><strong>ESO</strong> creates a local <strong>Kubernetes Secret</strong> with the fetched value.</p></li><li><p><strong>The Pod</strong> injects that secret as an environment variable (<code>MONGODB_PASSWORD</code>).</p></li></ul><p></p><h3>Why to use this ?</h3><ul><li><p><strong>Security</strong>: No secrets are stored in your Git repository or Terraform state in plain text.</p></li><li><p><strong>Automation</strong>: Change a password in AWS, and your app receives the update without a manual <code>kubectl apply</code>.</p></li><li><p><strong>Compliance</strong>: Centralize all your audit logs in AWS CloudTrail to see exactly who accessed which secret and when.</p></li></ul><h4>Synchronizing secret updates from AWS parameter store to Kubernetes</h4><p></p><p>Updating a password in the AWS Parameter Store doesn&#8217;t automatically reach your application pods because of how Kubernetes and the External Secrets Operator (ESO) work. The sync process happens in two distinct stages.</p><h3>Stage 1: AWS to Kubernetes (ESO Sync)</h3><p>The External Secrets Operator periodically &#8220;polls&#8221; AWS to check for updates. By default, this happens every <strong>1 hour</strong>, unless  specified a different <code>refreshInterval</code> in <code>ExternalSecret</code> manifest.</p><h4>To Sync Immediately (Force Refresh)</h4><p>If you don&#8217;t want to wait for the next polling cycle, you can force ESO to reconcile immediately by &#8220;touching&#8221; the <code>ExternalSecret</code> resource. The most common way is to add or update an annotation:</p><p><code>kubectl annotate externalsecret &lt;your-es-name&gt; force-sync=$(date +%s) --overwrite</code><br>Check the status of the sync to ensure it pulled the new value:</p><p><code>kubectl describe externalsecret &lt;your-es-name&gt;</code></p><p>Look for: Status: Ready, Message: Secret was synced</p><h3>Stage 2: Kubernetes Secret to Application Pods</h3><p>Even after the Kubernetes Secret is updated, your <strong>application pods likely still have the old password</strong> in memory.</p><ul><li><p><strong>If using Environment Variables:</strong> Kubernetes does <strong>not</strong> update environment variables in running containers. You must restart the pods to pick up the new value.</p><p><code>kubectl rollout restart deployment &lt;your-app-deployment&gt;</code></p></li></ul><ul><li><p><strong>If using Mounted Volumes:</strong> Kubernetes will eventually update the file in the pod (usually within 60 seconds), but your application code must be designed to &#8220;hot-reload&#8221; that file from disk. Most applications are not, so a restart is usually still required.</p></li></ul><p>To make this truly hands-off, many DevOps teams use a tool called <strong>Reloader</strong>. It watches Secrets and automatically triggers a <code>rollout restart</code> of Deployment whenever the Secret changes.</p><p>If you have Reloader installed, you just add this annotation to your Deployment:</p><pre><code>metadata:
  annotations:
    reloader.stakater.com/auto: "true"</code></pre><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading SysAdmin Journal! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/external-secrets-operator-eso-in?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/external-secrets-operator-eso-in?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/external-secrets-operator-eso-in/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/external-secrets-operator-eso-in/comments"><span>Leave a comment</span></a></p>]]></content:encoded></item><item><title><![CDATA[Securing On-Prem Jenkins with AWS IAM Roles Anywhere]]></title><description><![CDATA[For years, the standard way to connect a private server (like a Jenkins node) to AWS was to create an IAM User, generate an access_key_id and secret_access_key, and hide them in a config file.Those keys are permanent.]]></description><link>https://adminjournal.substack.com/p/securing-on-prem-jenkins-with-aws</link><guid isPermaLink="false">https://adminjournal.substack.com/p/securing-on-prem-jenkins-with-aws</guid><dc:creator><![CDATA[Драган Вучановић]]></dc:creator><pubDate>Tue, 27 Jan 2026 12:33:35 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!e2E6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f4eed6c-e96c-4d6c-83c3-72d246d06325_1016x897.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!e2E6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f4eed6c-e96c-4d6c-83c3-72d246d06325_1016x897.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!e2E6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f4eed6c-e96c-4d6c-83c3-72d246d06325_1016x897.png 424w, https://substackcdn.com/image/fetch/$s_!e2E6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f4eed6c-e96c-4d6c-83c3-72d246d06325_1016x897.png 848w, https://substackcdn.com/image/fetch/$s_!e2E6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f4eed6c-e96c-4d6c-83c3-72d246d06325_1016x897.png 1272w, https://substackcdn.com/image/fetch/$s_!e2E6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f4eed6c-e96c-4d6c-83c3-72d246d06325_1016x897.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!e2E6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f4eed6c-e96c-4d6c-83c3-72d246d06325_1016x897.png" width="1016" height="897" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9f4eed6c-e96c-4d6c-83c3-72d246d06325_1016x897.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:897,&quot;width&quot;:1016,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:950698,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/185951313?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f4eed6c-e96c-4d6c-83c3-72d246d06325_1016x897.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!e2E6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f4eed6c-e96c-4d6c-83c3-72d246d06325_1016x897.png 424w, https://substackcdn.com/image/fetch/$s_!e2E6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f4eed6c-e96c-4d6c-83c3-72d246d06325_1016x897.png 848w, https://substackcdn.com/image/fetch/$s_!e2E6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f4eed6c-e96c-4d6c-83c3-72d246d06325_1016x897.png 1272w, https://substackcdn.com/image/fetch/$s_!e2E6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f4eed6c-e96c-4d6c-83c3-72d246d06325_1016x897.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>For years, the standard way to connect a private server (like a Jenkins node) to AWS was to create an IAM User, generate an <code>access_key_id</code> and <code>secret_access_key</code>, and hide them in a config file.Those keys are permanent. If your server is compromised, those keys are stolen. If you forget to rotate them, you&#8217;re out of compliance. If you&#8217;re using a server with no public IP, you can&#8217;t even use OIDC easily because AWS can&#8217;t &#8220;call home&#8221; to verify your identity.</p><p><strong>AWS IAM Roles Anywhere</strong> treats your on-premises server like an EC2 instance. Instead of static keys, it uses <strong>Public Key Infrastructure (PKI)</strong>. Your server proves its identity using a digital certificate, and AWS hands back temporary, short-lived credentials.</p><p>To set this up, you just need:</p><ol><li><p><strong>A Trust Anchor:</strong> A Root Certificate Authority (CA) that you tell AWS to trust.</p></li><li><p><strong>An IAM Role:</strong> A role with a Trust Policy allowing <code>rolesanywhere.amazonaws.com</code> to assume it.</p></li><li><p><strong>A Profile:</strong> A configuration in AWS that links your Trust Anchor to your IAM Role.</p></li><li><p><strong>Client Certificates:</strong> A private key and certificate on your Jenkins server, signed by your Root CA.</p></li><li><p><strong>AWS Signing Helper:</strong> A small open-source tool from AWS that handles the &#8220;handshake.&#8221;</p></li></ol><h2><strong>The Workflow</strong></h2><ol><li><p><strong>Jenkins</strong> wants to run a Terraform plan.</p></li><li><p>The <strong>AWS CLI</strong> calls the <strong>Signing Helper</strong>.</p></li><li><p>The Helper signs a request using the local <strong>Private Key</strong>.</p></li><li><p><strong>AWS</strong> verifies the signature against the <strong>Trust Anchor</strong> and sends back temporary keys (valid for 1 hour).</p></li><li><p><strong>Jenkins</strong> performs the task and the keys expire automatically.</p></li></ol><h2><strong>Benefits vs. Disadvantages</strong></h2><h3><strong>The Benefits (Why you should do this)</strong></h3><ul><li><p><strong>Zero Static Secrets:</strong> No <code>AWS_ACCESS_KEY_ID</code> is ever stored on your disk.</p></li><li><p><strong>No Inbound Access Required:</strong> Perfect for servers behind strict firewalls or NAT.</p></li><li><p><strong>Auditability:</strong> Every login is logged in AWS CloudTrail, showing exactly which certificate was used.</p></li><li><p><strong>Automated Lifecycle:</strong> No more "Rotating Keys".When a certificate expires, the access simply stops.</p></li></ul><h3><strong>The Disadvantages</strong></h3><ul><li><p><strong>Initial Complexity:</strong> Setting up a Private CA (OpenSSL or AWS Private CA) takes more effort than clicking &#8220;Create Access Key.&#8221;</p></li><li><p><strong>Certificate Management:</strong> You are now responsible for renewing certificates before they expire. If your Root CA expires, all your servers lose access.</p></li><li><p><strong>Regionality:</strong> Roles Anywhere is a regional service. If you operate in multiple regions, you may need to set up Trust Anchors in each.</p></li></ul><h3><strong>Creating Private CA and certificates</strong></h3><p></p><pre><code># Switch to the jenkins user
sudo su -s /bin/bash jenkins

# Create a secure directory
mkdir -p ~/.aws_certs
cat &lt;&lt;EOF &gt; ca.conf
[ v3_ca ]
authorityKeyIdentifier=keyid,issuer
basicConstraints=critical,CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
subjectKeyIdentifier = hash
EOF
 
chmod 700 ~/.aws_certs
cd ~/.aws_certs

# Generate a root CA
openssl genrsa -out rootCA.key 2048
# Generate the Root Certificate with the v3_ca extensions
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 \
  -out rootCA.pem \
  -config &lt;(cat /etc/ssl/openssl.cnf ca.conf) \
  -extensions v3_ca \
  -subj "/C=US/ST=State/L=City/O=MyOrg/CN=MyPrivateRootCA"

cat &lt;&lt;EOF &gt; jenkins_ext.conf
authorityKeyIdentifier=keyid,issuer
basicConstraints=critical,CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
subjectKeyIdentifier = hash
EOF

# Create the Jenkins Private Key and CSR
openssl genrsa -out jenkins.key 2048
openssl req -new -key jenkins.key -out jenkins.csr -subj "/CN=jenkins-prod-01"

 
# Sign the Jenkins cert with Root CA
openssl x509 -req -in jenkins.csr -CA rootCA.pem -CAkey rootCA.key \
  -CAcreateserial -out jenkins.crt -days 365 -sha256 \
  -extfile jenkins_ext.conf


# Creating Jenkins server certificates
 
openssl x509 -req -in jenkins.csr -CA rootCA.pem -CAkey rootCA.key \
  -CAcreateserial -out jenkins.crt -days 365 -sha256 \
  -extfile jenkins_ext.conf</code></pre><p>Above commands set up a <strong>Private Mini-Certificate Authority (CA)</strong> on your server and use it to issue a unique &#8220;Security ID&#8221; (Certificate) to Jenkins so it can talk to AWS.</p><p>Here is the breakdown by section:</p><h5>1. Environment Setup</h5><ul><li><p><code>sudo su -s /bin/bash jenkins</code>: Switches your current session to the <code>jenkins</code> user so all files are owned by the right account.</p></li><li><p><code>mkdir</code><strong> &amp; </strong><code>chmod 700</code>: Creates a &#8220;vault&#8221; folder and locks it down so <strong>only</strong> the <code>jenkins</code> user can read the sensitive keys inside.</p></li></ul><h5>2. The Root CA (The "Stamp")</h5><ul><li><p><code>cat &lt;&lt;EOF &gt; ca.conf</code>: Writes the rules for your "Master Authority" (defining that it&#8217;s a CA).</p></li><li><p><code>openssl genrsa (rootCA.key)</code>: Creates the Master Private Key (the &#8220;seal&#8221; used to sign everything).</p></li><li><p><code>openssl req -x509 (rootCA.pem)</code>: Creates the actual Root Certificate&#8212;this is what you upload to AWS to tell them, &#8220;I trust any certificate signed by this file.&#8221;</p></li></ul><h5>3. Jenkins Identity Request (The "Application")</h5><ul><li><p><code>cat &lt;&lt;EOF &gt; jenkins_ext.conf</code>: Defines the specific &#8220;badges&#8221; (Digital Signature, Client Auth) AWS requires for a server to log in.</p></li><li><p><code>openssl genrsa (jenkins.key)</code>: Creates a unique private key just for the Jenkins server.</p></li><li><p><code>openssl req -new (jenkins.csr)</code>: Creates a Certificate Signing Request&#8212;essentially an "application form" that includes Jenkins&#8217; identity.</p></li></ul><h5>4. Issuing the ID (The "Signing&#8221;)</h5><ul><li><p><code>openssl x509 -req</code>: This is the final step where the <strong>Root CA</strong> "stamps" the <strong>Jenkins Application</strong>. It produces <code>jenkins.crt</code>, which is the actual ID card Jenkins will show to AWS to get temporary permissions.</p></li></ul><p></p><h3><strong>Creating Trusted anchor</strong></h3><p>In AWS console, in Search bar,type Roles anywhere-Create Trust anchor.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xI1Q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fe6af4e-c58a-464b-9b69-c8d8904257cf_1887x876.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xI1Q!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fe6af4e-c58a-464b-9b69-c8d8904257cf_1887x876.png 424w, https://substackcdn.com/image/fetch/$s_!xI1Q!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fe6af4e-c58a-464b-9b69-c8d8904257cf_1887x876.png 848w, https://substackcdn.com/image/fetch/$s_!xI1Q!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fe6af4e-c58a-464b-9b69-c8d8904257cf_1887x876.png 1272w, https://substackcdn.com/image/fetch/$s_!xI1Q!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fe6af4e-c58a-464b-9b69-c8d8904257cf_1887x876.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xI1Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fe6af4e-c58a-464b-9b69-c8d8904257cf_1887x876.png" width="1456" height="676" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1fe6af4e-c58a-464b-9b69-c8d8904257cf_1887x876.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:676,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:212418,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/185951313?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fe6af4e-c58a-464b-9b69-c8d8904257cf_1887x876.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xI1Q!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fe6af4e-c58a-464b-9b69-c8d8904257cf_1887x876.png 424w, https://substackcdn.com/image/fetch/$s_!xI1Q!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fe6af4e-c58a-464b-9b69-c8d8904257cf_1887x876.png 848w, https://substackcdn.com/image/fetch/$s_!xI1Q!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fe6af4e-c58a-464b-9b69-c8d8904257cf_1887x876.png 1272w, https://substackcdn.com/image/fetch/$s_!xI1Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fe6af4e-c58a-464b-9b69-c8d8904257cf_1887x876.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Select "External certificate bundler" and copy content of root CA file (rootCA.pem)</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LQhB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55b06dc8-ac17-4de2-93e1-0cf289eef763_1867x855.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LQhB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55b06dc8-ac17-4de2-93e1-0cf289eef763_1867x855.png 424w, https://substackcdn.com/image/fetch/$s_!LQhB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55b06dc8-ac17-4de2-93e1-0cf289eef763_1867x855.png 848w, https://substackcdn.com/image/fetch/$s_!LQhB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55b06dc8-ac17-4de2-93e1-0cf289eef763_1867x855.png 1272w, https://substackcdn.com/image/fetch/$s_!LQhB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55b06dc8-ac17-4de2-93e1-0cf289eef763_1867x855.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LQhB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55b06dc8-ac17-4de2-93e1-0cf289eef763_1867x855.png" width="1456" height="667" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/55b06dc8-ac17-4de2-93e1-0cf289eef763_1867x855.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:667,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:122540,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/185951313?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55b06dc8-ac17-4de2-93e1-0cf289eef763_1867x855.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!LQhB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55b06dc8-ac17-4de2-93e1-0cf289eef763_1867x855.png 424w, https://substackcdn.com/image/fetch/$s_!LQhB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55b06dc8-ac17-4de2-93e1-0cf289eef763_1867x855.png 848w, https://substackcdn.com/image/fetch/$s_!LQhB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55b06dc8-ac17-4de2-93e1-0cf289eef763_1867x855.png 1272w, https://substackcdn.com/image/fetch/$s_!LQhB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55b06dc8-ac17-4de2-93e1-0cf289eef763_1867x855.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Now click "Create a new role"-Custom trust policy.We need a role (Identity) that AWS "anywhere" is allowed to give to Jenkins server.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sP1k!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9240868f-02de-463e-89d5-2f1cf6533deb_1883x824.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sP1k!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9240868f-02de-463e-89d5-2f1cf6533deb_1883x824.png 424w, https://substackcdn.com/image/fetch/$s_!sP1k!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9240868f-02de-463e-89d5-2f1cf6533deb_1883x824.png 848w, https://substackcdn.com/image/fetch/$s_!sP1k!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9240868f-02de-463e-89d5-2f1cf6533deb_1883x824.png 1272w, https://substackcdn.com/image/fetch/$s_!sP1k!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9240868f-02de-463e-89d5-2f1cf6533deb_1883x824.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sP1k!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9240868f-02de-463e-89d5-2f1cf6533deb_1883x824.png" width="1456" height="637" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9240868f-02de-463e-89d5-2f1cf6533deb_1883x824.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:637,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:240370,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/185951313?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9240868f-02de-463e-89d5-2f1cf6533deb_1883x824.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!sP1k!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9240868f-02de-463e-89d5-2f1cf6533deb_1883x824.png 424w, https://substackcdn.com/image/fetch/$s_!sP1k!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9240868f-02de-463e-89d5-2f1cf6533deb_1883x824.png 848w, https://substackcdn.com/image/fetch/$s_!sP1k!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9240868f-02de-463e-89d5-2f1cf6533deb_1883x824.png 1272w, https://substackcdn.com/image/fetch/$s_!sP1k!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9240868f-02de-463e-89d5-2f1cf6533deb_1883x824.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Paste this code:</p><pre><code>{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "rolesanywhere.amazonaws.com"
            },
            "Action": [
                "sts:AssumeRole",
                "sts:TagSession",
                "sts:SetSourceIdentity"
            ]
        }
    ]
}</code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Sy0Q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe477110d-292a-4062-b42b-37f7a37edb27_1897x617.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Sy0Q!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe477110d-292a-4062-b42b-37f7a37edb27_1897x617.png 424w, https://substackcdn.com/image/fetch/$s_!Sy0Q!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe477110d-292a-4062-b42b-37f7a37edb27_1897x617.png 848w, https://substackcdn.com/image/fetch/$s_!Sy0Q!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe477110d-292a-4062-b42b-37f7a37edb27_1897x617.png 1272w, https://substackcdn.com/image/fetch/$s_!Sy0Q!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe477110d-292a-4062-b42b-37f7a37edb27_1897x617.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Sy0Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe477110d-292a-4062-b42b-37f7a37edb27_1897x617.png" width="1456" height="474" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e477110d-292a-4062-b42b-37f7a37edb27_1897x617.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:474,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:127116,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/185951313?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe477110d-292a-4062-b42b-37f7a37edb27_1897x617.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Sy0Q!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe477110d-292a-4062-b42b-37f7a37edb27_1897x617.png 424w, https://substackcdn.com/image/fetch/$s_!Sy0Q!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe477110d-292a-4062-b42b-37f7a37edb27_1897x617.png 848w, https://substackcdn.com/image/fetch/$s_!Sy0Q!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe477110d-292a-4062-b42b-37f7a37edb27_1897x617.png 1272w, https://substackcdn.com/image/fetch/$s_!Sy0Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe477110d-292a-4062-b42b-37f7a37edb27_1897x617.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>attach desired policy and give role a name (<code>Jenkins-RolesAnywhere-Role</code>). Save Role ARN.</p><h5>Create a Profile (The Connection)</h5><p>The Profile bridges <strong>Trust Anchor</strong> and <strong>Role</strong>.Click create a profile.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!x3HG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F802cb429-dc8a-4aa5-b372-45cb5cbfc665_1869x865.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!x3HG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F802cb429-dc8a-4aa5-b372-45cb5cbfc665_1869x865.png 424w, https://substackcdn.com/image/fetch/$s_!x3HG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F802cb429-dc8a-4aa5-b372-45cb5cbfc665_1869x865.png 848w, https://substackcdn.com/image/fetch/$s_!x3HG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F802cb429-dc8a-4aa5-b372-45cb5cbfc665_1869x865.png 1272w, https://substackcdn.com/image/fetch/$s_!x3HG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F802cb429-dc8a-4aa5-b372-45cb5cbfc665_1869x865.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!x3HG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F802cb429-dc8a-4aa5-b372-45cb5cbfc665_1869x865.png" width="1456" height="674" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/802cb429-dc8a-4aa5-b372-45cb5cbfc665_1869x865.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:674,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:240125,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/185951313?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F802cb429-dc8a-4aa5-b372-45cb5cbfc665_1869x865.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!x3HG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F802cb429-dc8a-4aa5-b372-45cb5cbfc665_1869x865.png 424w, https://substackcdn.com/image/fetch/$s_!x3HG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F802cb429-dc8a-4aa5-b372-45cb5cbfc665_1869x865.png 848w, https://substackcdn.com/image/fetch/$s_!x3HG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F802cb429-dc8a-4aa5-b372-45cb5cbfc665_1869x865.png 1272w, https://substackcdn.com/image/fetch/$s_!x3HG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F802cb429-dc8a-4aa5-b372-45cb5cbfc665_1869x865.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Select the role we just created (<code>Jenkins-RolesAnywhere-Role</code>),save Profile and Trusted anchor ARNs</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kaz3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bfb4ff1-6d8e-46b0-88d2-8580eb2990ca_1799x892.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kaz3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bfb4ff1-6d8e-46b0-88d2-8580eb2990ca_1799x892.png 424w, https://substackcdn.com/image/fetch/$s_!kaz3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bfb4ff1-6d8e-46b0-88d2-8580eb2990ca_1799x892.png 848w, https://substackcdn.com/image/fetch/$s_!kaz3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bfb4ff1-6d8e-46b0-88d2-8580eb2990ca_1799x892.png 1272w, https://substackcdn.com/image/fetch/$s_!kaz3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bfb4ff1-6d8e-46b0-88d2-8580eb2990ca_1799x892.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kaz3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bfb4ff1-6d8e-46b0-88d2-8580eb2990ca_1799x892.png" width="1456" height="722" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8bfb4ff1-6d8e-46b0-88d2-8580eb2990ca_1799x892.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:722,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:82716,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/185951313?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bfb4ff1-6d8e-46b0-88d2-8580eb2990ca_1799x892.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kaz3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bfb4ff1-6d8e-46b0-88d2-8580eb2990ca_1799x892.png 424w, https://substackcdn.com/image/fetch/$s_!kaz3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bfb4ff1-6d8e-46b0-88d2-8580eb2990ca_1799x892.png 848w, https://substackcdn.com/image/fetch/$s_!kaz3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bfb4ff1-6d8e-46b0-88d2-8580eb2990ca_1799x892.png 1272w, https://substackcdn.com/image/fetch/$s_!kaz3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bfb4ff1-6d8e-46b0-88d2-8580eb2990ca_1799x892.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>To obtain temporary security credentials from AWS Identity and Access Management Roles Anywhere, we  need credential helper tool that IAM Roles Anywhere provides.</p><pre><code>wget https://rolesanywhere.amazonaws.com/releases/1.7.3/X86_64/Linux/Amzn2023/aws_signing_helper
chmod +x aws_signing_helper &amp;&amp; mv aws_signing_helper /usr/local/bin/

# testing access

/usr/local/bin/aws_signing_helper credential-process \
  --certificate ~/.aws_certs/jenkins.crt \
  --private-key ~/.aws_certs/jenkins.key \
  --trust-anchor-arn Trusted-Anchor-ARN \
  --profile-arn profile-ARN \
  --role-arn Role-ARN</code></pre><p>If all is good,output should be long JSON output.</p><h5>Configuring the AWS CLI to use the Helper</h5><p>We need to tell the AWS CLI to "call" the signing helper whenever it needs to do something.</p><pre><code>sudo su -s /bin/bash jenkins
mkdir -p ~/.aws

cat &lt;&lt;EOF &gt; ~/.aws/config
[profile roles-anywhere]
region = eu-central-1
credential_process = /usr/local/bin/aws_signing_helper credential-process --certificate /var/lib/jenkins/.aws_certs/jenkins.crt --private-key /var/lib/jenkins/.aws_certs/jenkins.key --trust-anchor-arn arn:aws:rolesanywhere:eu-central-1:477568783935:trust-anchor/017451d4-1bdf-4ccb-88dd-86a07cdab61b --profile-arn arn:aws:rolesanywhere:eu-central-1:477568783935:profile/6f2e004f-cc1b-4d60-8047-0f301c06c3d5 --role-arn arn:aws:iam::477568783935:role/Jenkins-RolesAnywhere-Role
EOF</code></pre><p></p><p>Jenkins pipeline example how to use Role anywhere</p><pre><code> pipeline {
    agent any
    environment {
        // Force the AWS CLI to use the profile we created
        AWS_PROFILE = 'roles-anywhere'
    }
    stages {
        stage('AWS Task') {
            steps {
                // No 'withCredentials' block needed! 
                // The AWS CLI will trigger the signing helper automatically.
                sh 'aws s3 cp my-artifact.zip s3://my-jenkins-backups/'
            }
        }
    }
}</code></pre><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/securing-on-prem-jenkins-with-aws?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/securing-on-prem-jenkins-with-aws?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/securing-on-prem-jenkins-with-aws/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/securing-on-prem-jenkins-with-aws/comments"><span>Leave a comment</span></a></p><p></p><p> </p><p></p>]]></content:encoded></item><item><title><![CDATA[Connecting Jenkins pipeline to Azure ACR using Service Principal ]]></title><description><![CDATA[Connecting Jenkins to Azure Kubernetes Service (AKS) often leads developers toward using Client Secrets (passwords).]]></description><link>https://adminjournal.substack.com/p/connecting-jenkins-pipeline-to-azure</link><guid isPermaLink="false">https://adminjournal.substack.com/p/connecting-jenkins-pipeline-to-azure</guid><dc:creator><![CDATA[Драган Вучановић]]></dc:creator><pubDate>Wed, 17 Dec 2025 15:22:46 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!JmaZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa574bcad-dd4a-41fe-a812-12a825859f9a_1100x650.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JmaZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa574bcad-dd4a-41fe-a812-12a825859f9a_1100x650.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JmaZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa574bcad-dd4a-41fe-a812-12a825859f9a_1100x650.png 424w, https://substackcdn.com/image/fetch/$s_!JmaZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa574bcad-dd4a-41fe-a812-12a825859f9a_1100x650.png 848w, https://substackcdn.com/image/fetch/$s_!JmaZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa574bcad-dd4a-41fe-a812-12a825859f9a_1100x650.png 1272w, https://substackcdn.com/image/fetch/$s_!JmaZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa574bcad-dd4a-41fe-a812-12a825859f9a_1100x650.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JmaZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa574bcad-dd4a-41fe-a812-12a825859f9a_1100x650.png" width="1100" height="650" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a574bcad-dd4a-41fe-a812-12a825859f9a_1100x650.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:650,&quot;width&quot;:1100,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:565932,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/181894546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa574bcad-dd4a-41fe-a812-12a825859f9a_1100x650.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!JmaZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa574bcad-dd4a-41fe-a812-12a825859f9a_1100x650.png 424w, https://substackcdn.com/image/fetch/$s_!JmaZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa574bcad-dd4a-41fe-a812-12a825859f9a_1100x650.png 848w, https://substackcdn.com/image/fetch/$s_!JmaZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa574bcad-dd4a-41fe-a812-12a825859f9a_1100x650.png 1272w, https://substackcdn.com/image/fetch/$s_!JmaZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa574bcad-dd4a-41fe-a812-12a825859f9a_1100x650.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Connecting Jenkins to Azure Kubernetes Service (AKS) often leads developers toward using Client Secrets (passwords). However, for a &#8220;Least Privilege&#8221; security model, <strong>X.509 Certificates</strong> are the gold standard. In this post, I&#8217;ll show you how to bypass common plugin issues and build a robust, secure CI/CD pipeline.</p><p>Most tutorials suggest the Azure Credentials plugin, but it can often fail with <code>MissingPropertyException</code> or <code>null</code> path errors when handling certificates. Here i used more reliable method: the <strong>Secret File</strong> binding.</p><p>Jenkins server is located outside Azure (in this case, on-prem Hyper-V server as VM)</p><p>Create service principal with right to push images to Azure container registry</p><pre><code>az ad sp create-for-rbac --name jenkins-runner \
                         --role AcrPush \
                         --scopes $(az acr show --name myregistry205 --query id -o tsv) \
                         --create-cert</code></pre><p>Output should be like this</p><pre><code>&#8220;appId&#8221;: &#8220;33sasssS&#8221;,

  &#8220;displayName&#8221;: &#8220;jenkins-runner&#8221;,

  &#8220;fileWithCertAndPrivateKey&#8221;: &#8220;/var/lib/jenkins/tmpfzcl619j.pem&#8221;,

  &#8220;password&#8221;: null,

  &#8220;tenant&#8221;: &#8220;123-4445-tttttt&#8221;</code></pre><p>On Jenkins,store content of PEM file as secret file</p><p>Credentials-Kind: Secret file</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9AAV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc3a4561-ccbb-4d64-ab36-7687bb924114_2684x1510.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9AAV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc3a4561-ccbb-4d64-ab36-7687bb924114_2684x1510.png 424w, https://substackcdn.com/image/fetch/$s_!9AAV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc3a4561-ccbb-4d64-ab36-7687bb924114_2684x1510.png 848w, https://substackcdn.com/image/fetch/$s_!9AAV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc3a4561-ccbb-4d64-ab36-7687bb924114_2684x1510.png 1272w, https://substackcdn.com/image/fetch/$s_!9AAV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc3a4561-ccbb-4d64-ab36-7687bb924114_2684x1510.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9AAV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc3a4561-ccbb-4d64-ab36-7687bb924114_2684x1510.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bc3a4561-ccbb-4d64-ab36-7687bb924114_2684x1510.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:199740,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/181894546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc3a4561-ccbb-4d64-ab36-7687bb924114_2684x1510.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9AAV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc3a4561-ccbb-4d64-ab36-7687bb924114_2684x1510.png 424w, https://substackcdn.com/image/fetch/$s_!9AAV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc3a4561-ccbb-4d64-ab36-7687bb924114_2684x1510.png 848w, https://substackcdn.com/image/fetch/$s_!9AAV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc3a4561-ccbb-4d64-ab36-7687bb924114_2684x1510.png 1272w, https://substackcdn.com/image/fetch/$s_!9AAV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc3a4561-ccbb-4d64-ab36-7687bb924114_2684x1510.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Store TenantID and Azure Service principal AppID as Jenkins secrets (Credential type-Secret text)</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dCP7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e1926a8-ec3d-4615-b500-2ff5eb06b993_2298x260.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dCP7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e1926a8-ec3d-4615-b500-2ff5eb06b993_2298x260.png 424w, https://substackcdn.com/image/fetch/$s_!dCP7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e1926a8-ec3d-4615-b500-2ff5eb06b993_2298x260.png 848w, https://substackcdn.com/image/fetch/$s_!dCP7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e1926a8-ec3d-4615-b500-2ff5eb06b993_2298x260.png 1272w, https://substackcdn.com/image/fetch/$s_!dCP7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e1926a8-ec3d-4615-b500-2ff5eb06b993_2298x260.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dCP7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e1926a8-ec3d-4615-b500-2ff5eb06b993_2298x260.png" width="1456" height="165" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7e1926a8-ec3d-4615-b500-2ff5eb06b993_2298x260.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:165,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:45039,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/181894546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e1926a8-ec3d-4615-b500-2ff5eb06b993_2298x260.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dCP7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e1926a8-ec3d-4615-b500-2ff5eb06b993_2298x260.png 424w, https://substackcdn.com/image/fetch/$s_!dCP7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e1926a8-ec3d-4615-b500-2ff5eb06b993_2298x260.png 848w, https://substackcdn.com/image/fetch/$s_!dCP7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e1926a8-ec3d-4615-b500-2ff5eb06b993_2298x260.png 1272w, https://substackcdn.com/image/fetch/$s_!dCP7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e1926a8-ec3d-4615-b500-2ff5eb06b993_2298x260.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><pre><code>pipeline {
    agent any
   
    environment {
        REGISTRY_NAME = "myregistry205"
        IMAGE_NAME = "myapp"
        
    }
   stage('Build and push docker image') {
            steps {
                  withCredentials([file(credentialsId: 'azure-cert-pem', variable: 'CERT_FILE'),
                                  string(credentialsId: 'tenant_id', variable: 'TENANT_ID'),
                                  string(credentialsId: 'app_id', variable: 'CLIENT_ID')])
                {
                    script {
                        def fullImage = "${env.REGISTRY_NAME}.azurecr.io/${env.IMAGE_NAME}:${env.BUILD_NUMBER}"
                       
                        // 1. Build your image
                        sh "docker build -t ${fullImage} ./docker"
                        
                        sh '''
                            az login --service-principal \
                                -u ${env.CLIENT_ID} \
                                -t ${env.TENANT_ID} \
                                --certificate "${CERT_FILE}"
                        '''
                
                        sh "az acr login --name ${env.REGISTRY_NAME}"
                        sh "docker push ${fullImage}"
                      }
                }
            }
        }
     }
   
 post {
        success {
            echo "Image pushing to ACR successful!"
            
        }
        
        failure {
            echo "Pushing failed"
        }

        always {
            script {
                // 1. Always logout to clear the local Azure CLI token
                sh "az logout || true"
            }
            
            // 3. Clean the workspace files (keep this as the last step)
            cleanWs()
        }
    }
}</code></pre><p>The <code>az login</code> allows the Azure CLI to prove its identity so it can gain permission to push images to ACR or modify the AKS cluster.</p><pre><code><code>withCredentials([
    file(credentialsId: 'azure-cert-pem', variable: 'CERT_FILE'),
    string(credentialsId: 'tenant_id', variable: 'TENANT_ID'),
    string(credentialsId: 'app_id', variable: 'CLIENT_ID')
])
</code></code></pre><p>Jenkins fetches secrets from its encrypted database.</p><ul><li><p>For the certificate, Jenkins takes the binary uploaded data (PEM file content), writes it to a <strong>temporary file</strong> on the disk (e.g., <code>/tmp/secret123.pem</code>), and stores that path in the <code>CERT_FILE</code> variable.</p></li><li><p>As soon as the code inside the <code>{ }</code> block finishes, Jenkins <strong>deletes</strong> that temporary file</p></li></ul><pre><code><code>az login --service-principal \
    -u "$CLIENT_ID" \
    -t "$TENANT_ID" \
    --certificate "$CERT_FILE"
</code></code></pre><ul><li><p><code>--service-principal</code>: Tells Azure we're an application rather than a human user with an email/password.</p></li><li><p><code>-u &#8220;$CLIENT_ID&#8221;</code>: Application (Client) ID. This is like username.</p></li><li><p><code>-t &#8220;$TENANT_ID&#8221;</code>: Azure Directory ID. This tells the CLI which specific Azure organization to log into.</p></li><li><p><code>--certificate &#8220;$CERT_FILE&#8221;</code>: Instead of a password, the CLI uses the private key inside  <code>pem</code> file to sign a request. Azure validates this signature against the public key you uploaded to the App Registration.</p></li></ul><p>Once this command succeeds:</p><ol><li><p>An <strong>Access Token</strong> is stored in the <code>jenkins</code> user&#8217;s home directory (<code>~/.azure/msal_token_cache.bin</code>).</p></li><li><p>Subsequent commands like <code>az acr login</code> or <code>az aks get-credentials</code> look at that token to see if they are allowed to run.</p></li><li><p>Because we are logged in as a Service Principal, these commands will run <strong>non-interactively</strong> (no &#8220;Please open a browser&#8221; messages).</p><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/connecting-jenkins-pipeline-to-azure?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/connecting-jenkins-pipeline-to-azure?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/connecting-jenkins-pipeline-to-azure/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/connecting-jenkins-pipeline-to-azure/comments"><span>Leave a comment</span></a></p><p></p><p></p></li></ol><p></p><p></p><p></p><p></p><h2></h2>]]></content:encoded></item><item><title><![CDATA[Log Management on Amazon EKS: EFK Stack with ECK Operator and Fluent Bit]]></title><description><![CDATA[Unlike traditional Helm installs, using the ECK Operator allows Kubernetes to manage Elasticsearch as a native resource.]]></description><link>https://adminjournal.substack.com/p/log-management-on-amazon-eks-efk</link><guid isPermaLink="false">https://adminjournal.substack.com/p/log-management-on-amazon-eks-efk</guid><dc:creator><![CDATA[Драган Вучановић]]></dc:creator><pubDate>Tue, 16 Dec 2025 12:44:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!rC51!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d39a84c-2b0e-4039-ba9e-fcdb72ceef7d_1012x828.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rC51!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d39a84c-2b0e-4039-ba9e-fcdb72ceef7d_1012x828.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rC51!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d39a84c-2b0e-4039-ba9e-fcdb72ceef7d_1012x828.png 424w, https://substackcdn.com/image/fetch/$s_!rC51!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d39a84c-2b0e-4039-ba9e-fcdb72ceef7d_1012x828.png 848w, https://substackcdn.com/image/fetch/$s_!rC51!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d39a84c-2b0e-4039-ba9e-fcdb72ceef7d_1012x828.png 1272w, https://substackcdn.com/image/fetch/$s_!rC51!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d39a84c-2b0e-4039-ba9e-fcdb72ceef7d_1012x828.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rC51!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d39a84c-2b0e-4039-ba9e-fcdb72ceef7d_1012x828.png" width="1012" height="828" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5d39a84c-2b0e-4039-ba9e-fcdb72ceef7d_1012x828.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:828,&quot;width&quot;:1012,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1105448,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/181782410?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d39a84c-2b0e-4039-ba9e-fcdb72ceef7d_1012x828.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!rC51!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d39a84c-2b0e-4039-ba9e-fcdb72ceef7d_1012x828.png 424w, https://substackcdn.com/image/fetch/$s_!rC51!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d39a84c-2b0e-4039-ba9e-fcdb72ceef7d_1012x828.png 848w, https://substackcdn.com/image/fetch/$s_!rC51!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d39a84c-2b0e-4039-ba9e-fcdb72ceef7d_1012x828.png 1272w, https://substackcdn.com/image/fetch/$s_!rC51!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5d39a84c-2b0e-4039-ba9e-fcdb72ceef7d_1012x828.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Unlike traditional Helm installs, using the ECK Operator allows Kubernetes to manage Elasticsearch as a native resource. We&#8217;ve also swapped Fluentd for <strong>Fluent Bit</strong> to keep our resource footprint tiny, ensuring that logging doesn&#8217;t eat into our application&#8217;s CPU and RAM.</p><p>We use <code>volumeBindingMode: Immediate</code> to ensure storage is ready the moment Elasticsearch requests it.</p><p>Using the ECK Operator, our <code>elasticsearch.yaml</code> is surprisingly simple. The operator automatically handles the generation of internal TLS certificates and the default <code>elastic</code> user password.</p><ul><li><p><strong>Highlights:</strong> We&#8217;ve limited the JVM heap to 512MB (<code>ES_JAVA_OPTS</code>) to stay cost-effective while keeping the deployment stable with 10Gi of EBS storage.</p></li></ul><h3>Step 3: Visualizing with Kibana</h3><p>Kibana is our window into the logs. In <code>kibanaDeployment.yaml</code>, we don&#8217;t need to manually provide Elasticsearch URLs; the <code>elasticsearchRef</code> field tells the Operator to link them automatically.</p><ul><li><p><strong>Access:</strong> To make it reachable, we use <code>kibanaService.yaml</code> which creates an <strong>AWS LoadBalancer</strong>, giving us a public URL to access our dashboards.</p></li></ul><h3>Step 4: The Log Shipper (Fluent Bit)</h3><p>This is where the heavy lifting happens. We deploy Fluent Bit as a <strong>DaemonSet</strong>, meaning one pod runs on every single worker node in the EKS cluster.</p><ul><li><p><code>fluent-bit-DaemonSet.yaml</code> includes an <code>initContainer</code>. It &#8220;pings&#8221; Elasticsearch and waits for it to be fully healthy before Fluent Bit starts shipping logs. </p></li><li><p><strong>Security:</strong> We don&#8217;t hardcode passwords. Fluent Bit pulls the <code>ELASTIC_PASSWORD</code> directly from the Secret that the ECK Operator created.</p></li></ul><h3>Key Configuration: Fluent Bit Logic</h3><p>The magic is in the <code>fluent-bit-config.yaml</code>. We&#8217;ve broken it down into four stages:</p><h3>Input Section (<code>input-kubernetes.conf</code>)</h3><p>This section defines how Fluent Bit reads the raw log files from the Kubernetes nodes.</p><ul><li><p><strong>Name tail</strong>: Tells Fluent Bit to use the &#8220;tail&#8221; input plugin, which reads files like the Linux <code>tail</code> command.</p></li><li><p><strong>Path /var/log/containers/*.log</strong>: Specifies the exact location on the node where Kubernetes stores container logs.</p></li><li><p><strong>Tag kube.</strong>*: Assigns a tag starting with <code>kube.</code> to all logs collected from this path, allowing them to be targeted by specific filters later.</p></li><li><p><strong>Parser docker</strong>: Uses a predefined JSON parser to structure raw logs coming from Docker/CRI-O.</p></li><li><p><strong>Mem_Buf_Limit 5MB</strong>: Limits memory usage for this input to 5MB to prevent the Fluent Bit agent from consuming too much RAM.</p></li><li><p><strong>Skip_Long_Lines On</strong>: Skips lines that exceed the buffer size instead of crashing the plugin.</p></li><li><p><strong>DB /var/log/flb_kube.db</strong>: Maintains an SQLite database to track which parts of the log files have already been read, ensuring no logs are lost if the pod restarts.</p></li><li><p><strong>Read_from_Head False</strong>: Starts reading from the end of the file (new logs) rather than the beginning of old files.</p></li></ul><h3>2. Filter Section (<code>filter-kubernetes.conf</code>)</h3><p>This section enriches raw logs with Kubernetes-specific information like pod names, namespaces, and labels.</p><ul><li><p><strong>Name kubernetes</strong>: Uses the Kubernetes filter plugin to communicate with the API server.</p></li><li><p><strong>Match kube.</strong>*: Applies this filter only to logs that were tagged with <code>kube.</code> in the input step.</p></li><li><p><strong>Kube_URL / Kube_CA_File / Kube_Token_File</strong>: Standard credentials used by the filter to securely authenticate with the Kubernetes API.</p></li><li><p><strong>Kube_Tag_Prefix kube.var.log.containers.</strong>: Helps the filter extract the pod name and namespace directly from the file path.</p></li><li><p><strong>Merge_Log On / Merge_Log_Key log_processed</strong>: If the log is a JSON string, it merges those fields into the main log record under the key <code>log_processed</code>.</p></li><li><p><strong>Keep_Log Off</strong>: Discards the original unparsed &#8220;log&#8221; field after successful merging to save space.</p></li></ul><h3>3. Output Section (<code>output-elasticsearch.conf</code>)</h3><p>This section defines where the processed logs are sent for storage and visualization.</p><ul><li><p><strong>Name es</strong>: Uses the Elasticsearch output plugin.</p></li><li><p><strong>Host / Port</strong>: Points to the Elasticsearch service address and port (<code>9200</code>) within the cluster.</p></li><li><p><strong>Index / Logstash_Prefix k8s-logs</strong>: Sets the naming convention for the indices created in Elasticsearch.</p></li><li><p><strong>tls On / tls.verify On / tls.ca_file</strong>: Enables encrypted communication and specifies the certificate to verify the Elasticsearch server.</p></li><li><p><strong>HTTP_User / HTTP_Passwd</strong>: Authenticates with Elasticsearch using the default <code>elastic</code> user and a password pulled from a secure environment variable.</p></li><li><p><strong>Logstash_Format On</strong>: Formats the index names as <code>prefix-YYYY.MM.DD</code>, which is the standard format used by Kibana.</p></li><li><p><strong>Retry_Limit False</strong>: Tells Fluent Bit to keep trying to send logs if the connection to Elasticsearch is temporarily lost.</p></li></ul><p>Manifest files are available <a href="https://github.com/dragan1979/kubernetes-logging-efk/">here</a></p><h3>Prerequisites</h3><p>Install the ECK Operator</p><p>The Operator itself is installed cluster-wide. We&#8217;ll use the official manifest files from Elastic.These teach your Kubernetes cluster what an Elasticsearch and Kibana resource looks like.</p><pre><code>kubectl create -f https://download.elastic.co/downloads/eck/3.2.0/crds.yaml</code></pre><p>This deploys the actual Operator logic (the controller) into the elastic-system namespace.</p><pre><code>kubectl apply -f https://download.elastic.co/downloads/eck/3.2.0/operator.yaml</code></pre><p>Verify Operator Status:</p><pre><code>kubectl get -n elastic-system pods
NAME                 READY   STATUS    RESTARTS   AGE
elastic-operator-0   1/1     Running   0          135m</code></pre><p>Deploy EFK stack:</p><pre><code>kubectl apply -f namespace.yaml
kubectl apply -f storageClass.yaml
kubectl apply -f elasticsearch.yaml
kubectl apply -f kibanaService.yaml
kubectl apply -f kibanaDeployment.yaml
kubectl apply -f fluent-bit-RBAC.yaml
kubectl apply -f fluent-bit-config.yaml
kubectl apply -f fluent-bit-DaemonSet</code></pre><p>Check deployment:</p><pre><code>kubectl get all -n efklog
NAME                                     READY   STATUS    RESTARTS   AGE
pod/elasticsearch-logging-es-default-0   1/1     Running   0          108m
pod/fluent-bit-9qhsl                     1/1     Running   0          68m
pod/fluent-bit-cpvfb                     1/1     Running   0          68m
pod/kibana-logging-kb-658c9bb7bb-fcxjt   1/1     Running   0          79m

NAME                                             TYPE           CLUSTER-IP      EXTERNAL-IP                                                                PORT(S)          AGE
service/elasticsearch-logging-es-default         ClusterIP      None            &lt;none&gt;                                                                     9200/TCP         108m
service/elasticsearch-logging-es-http            ClusterIP      10.100.34.105   &lt;none&gt;                                                                     9200/TCP         108m
service/elasticsearch-logging-es-internal-http   ClusterIP      10.100.187.1    &lt;none&gt;                                                                     9200/TCP         108m
service/elasticsearch-logging-es-transport       ClusterIP      None            &lt;none&gt;                                                                     9300/TCP         108m
service/kibana-logging-external                  LoadBalancer   10.100.17.186   a37a47b7e1cd2441fa8d78dfb0e9b041-64884497.eu-central-1.elb.amazonaws.com   5601:31515/TCP   105m
service/kibana-logging-kb-http                   ClusterIP      10.100.38.21    &lt;none&gt;                                                                     5601/TCP         79m

NAME                        DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
daemonset.apps/fluent-bit   2         2         2       2            2           &lt;none&gt;          76m

NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/kibana-logging-kb   1/1     1            1           79m

NAME                                           DESIRED   CURRENT   READY   AGE
replicaset.apps/kibana-logging-kb-658c9bb7bb   1         1         1       79m

NAME                                                READY   AGE
statefulset.apps/elasticsearch-logging-es-default   1/1     108m</code></pre><p>Get Kibana password:</p><pre><code>kubectl get secret elasticsearch-logging-es-elastic-user -n efklog -o jsonpath=&#8217;{.data.elastic}&#8217; | base64 --decode</code></pre><p>Login to Kibana Web Gui using Load Balancer service </p><p>https://<code>a37a47b7e1cd2441fa8d78dfb0e9b041-64884497.eu-central-1.elb.amazonaws.com:5601 in this case, username elastic</code></p><p>password from above step</p><pre><code>kubectl get svc -n efklog
NAME                                     TYPE           CLUSTER-IP      EXTERNAL-IP                                                                PORT(S)          AGE
elasticsearch-logging-es-default         ClusterIP      None            &lt;none&gt;                                                                     9200/TCP         110m
elasticsearch-logging-es-http            ClusterIP      10.100.34.105   &lt;none&gt;                                                                     9200/TCP         110m
elasticsearch-logging-es-internal-http   ClusterIP      10.100.187.1    &lt;none&gt;                                                                     9200/TCP         110m
elasticsearch-logging-es-transport       ClusterIP      None            &lt;none&gt;                                                                     9300/TCP         110m
kibana-logging-external                  LoadBalancer   10.100.17.186   a37a47b7e1cd2441fa8d78dfb0e9b041-64884497.eu-central-1.elb.amazonaws.com   5601:31515/TCP   107m
kibana-logging-kb-http                   ClusterIP      10.100.38.21    &lt;none&gt;                                                                     5601/TCP         81m</code></pre><p>When you access Kibana, the certificate warning occurs because the <strong>ECK (Elastic Cloud on Kubernetes) Operator</strong> automatically generates a <strong>self-signed CA</strong> to secure communication. Since your browser does not recognize or trust this internal Elastic CA, it flags the connection as &#8220;Not Secure.&#8221;</p><p>To resolve this and use your own trusted certificate (e.g., from Let&#8217;s Encrypt or your organization&#8217;s CA), you need to provide your certificate as a Kubernetes Secret and update the Kibana resource.First, you must package your certificate (<code>tls.crt</code>) and private key (<code>tls.key</code>) into a Secret within the <code>efklog</code> namespace.</p><pre><code>kubectl create secret tls kibana-custom-cert \
  --cert=path/to/your/cert.crt \
  --key=path/to/your/key.key \
  -n efklog</code></pre><p></p><p>We need to modify Kibana manifest (similar to <code>elasticsearch.yaml</code> structure) to tell the Operator to use your secret instead of generating its own.</p><p>Add the <code>http</code> section under <code>spec</code>:</p><pre><code>apiVersion: kibana.k8s.elastic.co/v1
kind: Kibana
metadata:
  name: kibana-logging
  namespace: efklog
spec:
  version: 8.12.2
  count: 1
  elasticsearchRef:
    name: elasticsearch-logging
  http:
    tls:
      selfSignedCertificate:
        disabled: true  # Disable the auto-generated cert
      certificate:
        secretName: kibana-custom-cert # Use your created secret</code></pre><p>In Kibana Dashboard-Kibana-Data views-Create Data view</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hmVj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87e693b5-488d-4b0a-8bcf-62b1158c7a4d_2586x1640.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hmVj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87e693b5-488d-4b0a-8bcf-62b1158c7a4d_2586x1640.png 424w, https://substackcdn.com/image/fetch/$s_!hmVj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87e693b5-488d-4b0a-8bcf-62b1158c7a4d_2586x1640.png 848w, https://substackcdn.com/image/fetch/$s_!hmVj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87e693b5-488d-4b0a-8bcf-62b1158c7a4d_2586x1640.png 1272w, https://substackcdn.com/image/fetch/$s_!hmVj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87e693b5-488d-4b0a-8bcf-62b1158c7a4d_2586x1640.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hmVj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87e693b5-488d-4b0a-8bcf-62b1158c7a4d_2586x1640.png" width="1456" height="923" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/87e693b5-488d-4b0a-8bcf-62b1158c7a4d_2586x1640.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:923,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:403713,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/181782410?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87e693b5-488d-4b0a-8bcf-62b1158c7a4d_2586x1640.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!hmVj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87e693b5-488d-4b0a-8bcf-62b1158c7a4d_2586x1640.png 424w, https://substackcdn.com/image/fetch/$s_!hmVj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87e693b5-488d-4b0a-8bcf-62b1158c7a4d_2586x1640.png 848w, https://substackcdn.com/image/fetch/$s_!hmVj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87e693b5-488d-4b0a-8bcf-62b1158c7a4d_2586x1640.png 1272w, https://substackcdn.com/image/fetch/$s_!hmVj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87e693b5-488d-4b0a-8bcf-62b1158c7a4d_2586x1640.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><ul><li><p><strong>Name:</strong> Enter a name (e.g., <code>k8s-logs-new</code>).</p></li><li><p><strong>Index pattern:</strong> Enter <code>k8s-logs-*</code>. This must match the <code>Logstash_Prefix</code> defined in your <code>output-elasticsearch.conf</code>.</p></li><li><p><strong>Timestamp field:</strong> Select <code>@timestamp</code> from the dropdown menu.</p></li><li><p>Click <strong>Save data view to Kibana</strong>.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Nekv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bbbb02a-20b0-43c7-935d-fd8f1355f609_1756x1626.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Nekv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bbbb02a-20b0-43c7-935d-fd8f1355f609_1756x1626.png 424w, https://substackcdn.com/image/fetch/$s_!Nekv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bbbb02a-20b0-43c7-935d-fd8f1355f609_1756x1626.png 848w, https://substackcdn.com/image/fetch/$s_!Nekv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bbbb02a-20b0-43c7-935d-fd8f1355f609_1756x1626.png 1272w, https://substackcdn.com/image/fetch/$s_!Nekv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bbbb02a-20b0-43c7-935d-fd8f1355f609_1756x1626.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Nekv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bbbb02a-20b0-43c7-935d-fd8f1355f609_1756x1626.png" width="1456" height="1348" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7bbbb02a-20b0-43c7-935d-fd8f1355f609_1756x1626.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1348,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:250055,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/181782410?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bbbb02a-20b0-43c7-935d-fd8f1355f609_1756x1626.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Nekv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bbbb02a-20b0-43c7-935d-fd8f1355f609_1756x1626.png 424w, https://substackcdn.com/image/fetch/$s_!Nekv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bbbb02a-20b0-43c7-935d-fd8f1355f609_1756x1626.png 848w, https://substackcdn.com/image/fetch/$s_!Nekv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bbbb02a-20b0-43c7-935d-fd8f1355f609_1756x1626.png 1272w, https://substackcdn.com/image/fetch/$s_!Nekv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bbbb02a-20b0-43c7-935d-fd8f1355f609_1756x1626.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0Ddb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dd9a353-505c-46ba-9271-2991cd017625_2712x1584.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0Ddb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dd9a353-505c-46ba-9271-2991cd017625_2712x1584.png 424w, https://substackcdn.com/image/fetch/$s_!0Ddb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dd9a353-505c-46ba-9271-2991cd017625_2712x1584.png 848w, https://substackcdn.com/image/fetch/$s_!0Ddb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dd9a353-505c-46ba-9271-2991cd017625_2712x1584.png 1272w, https://substackcdn.com/image/fetch/$s_!0Ddb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dd9a353-505c-46ba-9271-2991cd017625_2712x1584.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0Ddb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dd9a353-505c-46ba-9271-2991cd017625_2712x1584.png" width="1456" height="850" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1dd9a353-505c-46ba-9271-2991cd017625_2712x1584.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:850,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:367111,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/181782410?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dd9a353-505c-46ba-9271-2991cd017625_2712x1584.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0Ddb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dd9a353-505c-46ba-9271-2991cd017625_2712x1584.png 424w, https://substackcdn.com/image/fetch/$s_!0Ddb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dd9a353-505c-46ba-9271-2991cd017625_2712x1584.png 848w, https://substackcdn.com/image/fetch/$s_!0Ddb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dd9a353-505c-46ba-9271-2991cd017625_2712x1584.png 1272w, https://substackcdn.com/image/fetch/$s_!0Ddb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1dd9a353-505c-46ba-9271-2991cd017625_2712x1584.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><ul><li><p>Click the <strong>Hamburger Menu (&#9776;)</strong> and go to <strong>Analytics</strong> &gt; <strong>Discover</strong>.</p></li><li><p>Ensure your new data view is selected in the dropdown on the left.</p></li><li><p>You should now see a clean timeline of logs coming from your EKS cluster.</p><p></p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MvJv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b4c3d9-d743-4480-ad9b-7ab6af2d9801_2726x1468.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MvJv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b4c3d9-d743-4480-ad9b-7ab6af2d9801_2726x1468.png 424w, https://substackcdn.com/image/fetch/$s_!MvJv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b4c3d9-d743-4480-ad9b-7ab6af2d9801_2726x1468.png 848w, https://substackcdn.com/image/fetch/$s_!MvJv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b4c3d9-d743-4480-ad9b-7ab6af2d9801_2726x1468.png 1272w, https://substackcdn.com/image/fetch/$s_!MvJv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b4c3d9-d743-4480-ad9b-7ab6af2d9801_2726x1468.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MvJv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b4c3d9-d743-4480-ad9b-7ab6af2d9801_2726x1468.png" width="1456" height="784" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e7b4c3d9-d743-4480-ad9b-7ab6af2d9801_2726x1468.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:784,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:496956,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/181782410?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b4c3d9-d743-4480-ad9b-7ab6af2d9801_2726x1468.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!MvJv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b4c3d9-d743-4480-ad9b-7ab6af2d9801_2726x1468.png 424w, https://substackcdn.com/image/fetch/$s_!MvJv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b4c3d9-d743-4480-ad9b-7ab6af2d9801_2726x1468.png 848w, https://substackcdn.com/image/fetch/$s_!MvJv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b4c3d9-d743-4480-ad9b-7ab6af2d9801_2726x1468.png 1272w, https://substackcdn.com/image/fetch/$s_!MvJv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe7b4c3d9-d743-4480-ad9b-7ab6af2d9801_2726x1468.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/log-management-on-amazon-eks-efk?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/log-management-on-amazon-eks-efk?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/log-management-on-amazon-eks-efk/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/log-management-on-amazon-eks-efk/comments"><span>Leave a comment</span></a></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Azure DevOps CI/CD workflow with Terraform, MSI, and Azure Slot Swaps ]]></title><description><![CDATA[The code provided defines a comprehensive Azure DevOps Continuous Integration/Continuous Deployment (CI/CD) pipeline that automates the deployment of both infrastructure (Infrastructure as Code) and a .NET web application to Azure, following a secure Git flow branching strategy (]]></description><link>https://adminjournal.substack.com/p/azure-devops-cicd-workflow-with-terraform</link><guid isPermaLink="false">https://adminjournal.substack.com/p/azure-devops-cicd-workflow-with-terraform</guid><dc:creator><![CDATA[Драган Вучановић]]></dc:creator><pubDate>Wed, 10 Dec 2025 11:18:17 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!hGVh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cae51a2-edfe-424d-82e0-a3af98274e44_1226x895.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hGVh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cae51a2-edfe-424d-82e0-a3af98274e44_1226x895.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hGVh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cae51a2-edfe-424d-82e0-a3af98274e44_1226x895.png 424w, https://substackcdn.com/image/fetch/$s_!hGVh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cae51a2-edfe-424d-82e0-a3af98274e44_1226x895.png 848w, https://substackcdn.com/image/fetch/$s_!hGVh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cae51a2-edfe-424d-82e0-a3af98274e44_1226x895.png 1272w, https://substackcdn.com/image/fetch/$s_!hGVh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cae51a2-edfe-424d-82e0-a3af98274e44_1226x895.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hGVh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cae51a2-edfe-424d-82e0-a3af98274e44_1226x895.png" width="1226" height="895" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8cae51a2-edfe-424d-82e0-a3af98274e44_1226x895.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:895,&quot;width&quot;:1226,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:399080,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/181224043?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cae51a2-edfe-424d-82e0-a3af98274e44_1226x895.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!hGVh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cae51a2-edfe-424d-82e0-a3af98274e44_1226x895.png 424w, https://substackcdn.com/image/fetch/$s_!hGVh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cae51a2-edfe-424d-82e0-a3af98274e44_1226x895.png 848w, https://substackcdn.com/image/fetch/$s_!hGVh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cae51a2-edfe-424d-82e0-a3af98274e44_1226x895.png 1272w, https://substackcdn.com/image/fetch/$s_!hGVh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8cae51a2-edfe-424d-82e0-a3af98274e44_1226x895.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><a href="https://github.com/dragan1979/azuredevops-terraform-net">The code provided</a> defines a comprehensive Azure DevOps Continuous Integration/Continuous Deployment (CI/CD) pipeline that automates the deployment of both infrastructure (Infrastructure as Code) and a .NET web application to Azure, following a secure Git flow branching strategy (<code>develop</code> and <code>main</code>).</p><p>The overall process is to:</p><ol><li><p><strong>Build and Test</strong> the application.</p></li><li><p><strong>Scan</strong> the infrastructure code for security issues.</p></li><li><p><strong>Deploy</strong> the infrastructure (Azure SQL, Web App networking, etc.) using <strong>Terraform</strong>.</p></li><li><p><strong>Deploy</strong> the web application to the Azure Web App, using a Blue/Green (slot swap) strategy for zero-downtime deployment.</p></li><li><p>Secure the application&#8217;s database connection using <strong>Managed Identity</strong> (MSI) to eliminate the need for storing secrets.</p></li></ol><div><hr></div><h2>1. CI/CD Pipeline Flow</h2><p><a href="https://github.com/dragan1979/azuredevops-terraform-net/blob/main/azure-pipelines.yaml">The pipeline</a> is structured into multiple stages that run conditionally based on the branch:</p><h3>A. CI Stages (Runs on both <code>develop</code> and <code>main</code>)</h3><ul><li><p><code>CI_Build_and_Tests</code><strong>:</strong></p><ul><li><p>Installs the .NET 8.0 SDK.</p></li><li><p>Restores NuGet packages and runs unit tests.</p></li><li><p>Calculates and publishes code coverage results and generates an HTML report.</p></li><li><p>Builds and publishes the final web application as a deployable artifact named <code>drop</code>.</p></li></ul></li><li><p><code>Static_Analysis_Checks</code><strong>:</strong></p><ul><li><p>Installs <code>TFLint</code> and <code>Checkov</code> tools.</p></li><li><p>Runs <strong>TFLint</strong> to lint the Terraform files for syntax and style compliance.</p></li><li><p>Runs <strong>Checkov</strong> to scan the infrastructure code for cloud security and compliance errors.</p></li><li><p>Publishes the security reports (JSON/HTML) as artifacts for review.</p></li></ul></li></ul><h3>B. Development Environment Flow (Runs on <code>develop</code> branch)</h3><ul><li><p><code>Deploy_Development_Infra</code><strong>:</strong></p><ul><li><p>Installs Terraform and the <code>sqlcmd</code> utility (required for database setup).</p></li><li><p>Runs <code>terraform init</code>, <code>plan</code>, and <code>apply</code> to provision the Development infrastructure using Azure Service Principal credentials (<code>ARM_CLIENT_ID</code>, etc.).</p></li></ul></li><li><p><code>Deploy_Development_Config</code><strong>:</strong></p><ul><li><p>Retrieves the provisioned infrastructure outputs (SQL FQDN, DB Name, Web App Name) from Terraform state.</p></li><li><p><strong>Assembles the SQL Connection String</strong> and sets it as an output variable (<code>CONN_STRING</code>).</p><ul><li><p>It accepts <code>User ID=$SQL_USER;Password=$SQL_PASSWORD;</code> but can use Managed Identity format (<code>Authentication=Active Directory Managed Identity;</code>).</p></li></ul></li></ul></li><li><p><code>Deploy_Web_App</code><strong>:</strong></p><ul><li><p>Downloads the application artifact (<code>drop</code>).</p></li><li><p>Deploys the application code to the <strong>staging slot</strong> of the Web App, injecting the connection string as an App Setting (<code>-ConnectionStrings__DefaultConnection</code>).</p></li><li><p>Performs a <strong>slot swap</strong> (<code>AzureAppServiceManage@0</code>) to move the newly deployed code from <code>staging</code> to <code>production</code>, completing the blue/green deployment for the Development environment.</p></li></ul></li></ul><h3>C. Production Environment Flow (Runs on <code>main</code> branch)</h3><p>This flow utilizes a gated deployment pattern, separating plan, approval, and application.</p><ul><li><p><code>Plan_Prod_Infra</code><strong>:</strong> Runs <code>terraform init</code> and <code>terraform plan</code> for the Production environment and publishes the <code>plan.out</code> artifact for mandatory review (e.g., via a manual approval gate in a subsequent stage).</p></li><li><p><code>Deploy_Prod_Infra</code><strong>:</strong> Downloads the previously approved <code>plan.out</code> artifact and executes <code>terraform apply</code> to provision the Production infrastructure.</p></li><li><p><code>Deploy_Staging_Config</code><strong>:</strong> Identical to the Development config stage, retrieving Production outputs and assembling the connection string.</p></li><li><p><code>Deploy_Web_App_Staging</code><strong>:</strong> Deploys the application code to the <strong>staging slot</strong> of the Production Web App.</p></li><li><p><code>Deploy_Production_Swap</code><strong>:</strong> This stage is designed to be the final gate. It performs the <strong>slot swap</strong> from <code>staging</code> to <code>production</code> in the production environment. This stage is typically linked to a manual approval in the Azure DevOps environment to ensure a human confirms the deployment before affecting live traffic.</p></li></ul><div><hr></div><h2>2. Infrastructure as Code (Terraform) Functionality</h2><p>The fundamental reason for needing the separate <strong>Azure DevOps Variable Group</strong> (containing <code>client_id</code>, <code>client_secret</code>, and <code>tenant_id</code>) is that the standard Azure DevOps Service Connection mechanism <strong>does not expose the Service Principal&#8217;s secrets</strong> to the pipeline tasks that need them.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fT9Q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6efac336-371c-47ca-8cff-0a25e60a748f_1359x983.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fT9Q!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6efac336-371c-47ca-8cff-0a25e60a748f_1359x983.png 424w, https://substackcdn.com/image/fetch/$s_!fT9Q!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6efac336-371c-47ca-8cff-0a25e60a748f_1359x983.png 848w, https://substackcdn.com/image/fetch/$s_!fT9Q!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6efac336-371c-47ca-8cff-0a25e60a748f_1359x983.png 1272w, https://substackcdn.com/image/fetch/$s_!fT9Q!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6efac336-371c-47ca-8cff-0a25e60a748f_1359x983.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fT9Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6efac336-371c-47ca-8cff-0a25e60a748f_1359x983.png" width="1359" height="983" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6efac336-371c-47ca-8cff-0a25e60a748f_1359x983.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:983,&quot;width&quot;:1359,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:79070,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/181224043?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6efac336-371c-47ca-8cff-0a25e60a748f_1359x983.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!fT9Q!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6efac336-371c-47ca-8cff-0a25e60a748f_1359x983.png 424w, https://substackcdn.com/image/fetch/$s_!fT9Q!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6efac336-371c-47ca-8cff-0a25e60a748f_1359x983.png 848w, https://substackcdn.com/image/fetch/$s_!fT9Q!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6efac336-371c-47ca-8cff-0a25e60a748f_1359x983.png 1272w, https://substackcdn.com/image/fetch/$s_!fT9Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6efac336-371c-47ca-8cff-0a25e60a748f_1359x983.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The Terraform files define the Azure resources and their secure configuration:</p><ul><li><p><strong>Azure SQL Server and Database:</strong> Creates an Azure SQL Server with an Azure AD Administrator configured. The server is configured with a <strong>System-Assigned Managed Identity (MSI)</strong>.</p></li><li><p><strong>Database User Mapping (MSI):</strong> Uses the <code>mssql_user</code> resource to create a user inside the SQL Database that is explicitly mapped to the Azure Web App&#8217;s Managed Identity (<code>var.webapp_principal_id</code>), granting it <code>db_datareader</code> and <code>db_datawriter</code> roles. This is the key step for secrets-less application authentication.</p></li><li><p><strong>Database Schema Initialization:</strong> The <code>null_resource</code> executes the <code>setup.sql</code> script via the <code>sqlcmd</code> utility, using <strong>Active Directory Service Principal</strong> authentication, to create the initial <code>Artifacts</code> table and insert sample data.</p></li><li><p><strong>Networking:</strong> Enforces security by creating an Azure Private Endpoint for the SQL Server, linking it to a Virtual Network via a Private DNS Zone (<code>privatelink.database.windows.net</code>), ensuring that database traffic stays within the private Azure network.</p></li><li><p><strong>Role Assignment:</strong> Assigns the SQL Server&#8217;s own System-Assigned Managed Identity to the <strong>Directory Readers</strong> Azure AD role, which is a common requirement for Azure SQL to resolve external Azure AD users (like the Web App&#8217;s MSI).</p></li><li><p>A main Virtual Network is created and segmented into two purpose-built subnets:</p><ul><li><p><strong>Web App Subnet:</strong> Specifically delegated (<code>Microsoft.Web/serverFarms</code>) for App Service VNet Integration, which allows the Web App to join the private network.</p></li><li><p><strong>Private Endpoint Subnet:</strong> A separate, dedicated subnet is reserved for hosting the Private Endpoint connection to the Azure SQL Database.</p></li></ul></li><li><p><strong>Network Security Group (NSG) Enforcement:</strong> A stringent Network Security Group (<code>azurerm_network_security_group.webapp_sql_nsg</code>) is created and associated with the Web App Subnet. This acts as a private firewall, controlling all incoming and outgoing traffic:</p><ul><li><p><strong>Inbound Denial:</strong> Explicitly denies all inbound traffic from the public Internet (<code>Internet</code> Service Tag), ensuring the Web App is only accessible via Azure&#8217;s internal services or an authorized front door.</p></li><li><p><strong>Outbound SQL Access:</strong> Limits outbound traffic to port <strong>1433</strong> (SQL) only when the destination is within the Virtual Network (<code>VirtualNetwork</code> Service Tag). This means the application can <em>only</em> connect to the Azure SQL Private Endpoint, blocking connections to any public SQL server.</p></li><li><p><strong>Outbound Security Access:</strong> Explicitly permits outbound HTTPS (port 443) traffic to the <strong>AzureActiveDirectory</strong> Service Tag (required for the Web App to acquire Managed Identity tokens) and the <strong>AzureKeyVault</strong> Service Tag (if the application needs to fetch other configuration secrets).</p></li></ul></li></ul><p>While the network configuration locks down where the Web App can connect, the infrastructure code also prepares for <strong>who</strong> can connect to the database.</p><ul><li><p><strong>SQL Server &amp; Web App Identity (Setup):</strong> This infrastructure is designed to be paired with a Web App that uses a <strong>System-Assigned Managed Identity</strong>.</p></li><li><p><strong>Automated User Mapping:</strong> The process includes using the Web App&#8217;s Managed Identity Principal ID (retrieved from an output variable) to automatically create a corresponding user within the SQL Database itself. This step grants the Web App&#8217;s identity specific roles (like <code>db_datareader</code> and <code>db_datawriter</code>), establishing a principle of least privilege.</p></li><li><p><strong>The Result:</strong> The application&#8217;s final connection string will not contain any username or password, relying entirely on the Azure platform to exchange the Managed Identity for a temporary, secure access token.</p></li></ul><p>Code link: <a href="https://github.com/dragan1979/azuredevops-terraform-net/blob/main/azure-pipelines.yaml">here</a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/azure-devops-cicd-workflow-with-terraform?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/azure-devops-cicd-workflow-with-terraform?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/azure-devops-cicd-workflow-with-terraform/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/azure-devops-cicd-workflow-with-terraform/comments"><span>Leave a comment</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Automating Terraform AWS deployment with GitHub Actions - A Two-Stage CI/CD Pipeline using CDKTF - Python]]></title><description><![CDATA[This repository provides a modular, reusable Terraform module for provisioning a standard, highly available AWS Virtual Private Cloud (VPC) with public and private subnets across multiple Availability Zones (AZs).]]></description><link>https://adminjournal.substack.com/p/automating-terraform-aws-deployment</link><guid isPermaLink="false">https://adminjournal.substack.com/p/automating-terraform-aws-deployment</guid><dc:creator><![CDATA[Драган Вучановић]]></dc:creator><pubDate>Thu, 20 Nov 2025 14:35:43 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!DiUQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb839a950-b7e0-4202-8e91-73902570162d_471x428.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DiUQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb839a950-b7e0-4202-8e91-73902570162d_471x428.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DiUQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb839a950-b7e0-4202-8e91-73902570162d_471x428.png 424w, https://substackcdn.com/image/fetch/$s_!DiUQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb839a950-b7e0-4202-8e91-73902570162d_471x428.png 848w, https://substackcdn.com/image/fetch/$s_!DiUQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb839a950-b7e0-4202-8e91-73902570162d_471x428.png 1272w, https://substackcdn.com/image/fetch/$s_!DiUQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb839a950-b7e0-4202-8e91-73902570162d_471x428.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DiUQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb839a950-b7e0-4202-8e91-73902570162d_471x428.png" width="471" height="428" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b839a950-b7e0-4202-8e91-73902570162d_471x428.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:428,&quot;width&quot;:471,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:356204,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/179454478?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb839a950-b7e0-4202-8e91-73902570162d_471x428.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!DiUQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb839a950-b7e0-4202-8e91-73902570162d_471x428.png 424w, https://substackcdn.com/image/fetch/$s_!DiUQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb839a950-b7e0-4202-8e91-73902570162d_471x428.png 848w, https://substackcdn.com/image/fetch/$s_!DiUQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb839a950-b7e0-4202-8e91-73902570162d_471x428.png 1272w, https://substackcdn.com/image/fetch/$s_!DiUQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb839a950-b7e0-4202-8e91-73902570162d_471x428.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><a href="https://github.com/dragan1979/aws-githhub-actions">This repository</a> provides a modular, reusable <strong>Terraform module</strong> for provisioning a standard, highly available AWS Virtual Private Cloud (VPC) with public and private subnets across multiple Availability Zones (AZs).</p><p>The Terraform module creates a best-practice VPC topology designed for high availability and security:</p><ul><li><p><strong>VPC</strong>: The main network container.</p></li><li><p><strong>Public Subnets</strong>: Provisioned for public-facing resources (e.g., Load Balancers) and spread across multiple AZs.</p></li><li><p><strong>Private Subnets</strong>: Provisioned for application servers and databases, providing isolated, secure network space.</p></li><li><p><strong>Internet Gateway (IGW)</strong>: Provides internet access for the VPC.</p></li><li><p><strong>NAT Gateways (NAT-GWs)</strong>: One NAT-GW is deployed in <em>each</em> public subnet, allowing resources in the private subnets to initiate outbound internet traffic (e.g., for updates) without being publicly accessible.</p></li><li><p><strong>Routing</strong>: Public subnets route directly to the IGW, while each Private Subnet routes to its corresponding NAT-GW within the same AZ index.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!B0r3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66850902-3b61-4b4e-ba6d-f660dc6af925_861x249.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!B0r3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66850902-3b61-4b4e-ba6d-f660dc6af925_861x249.png 424w, https://substackcdn.com/image/fetch/$s_!B0r3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66850902-3b61-4b4e-ba6d-f660dc6af925_861x249.png 848w, https://substackcdn.com/image/fetch/$s_!B0r3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66850902-3b61-4b4e-ba6d-f660dc6af925_861x249.png 1272w, https://substackcdn.com/image/fetch/$s_!B0r3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66850902-3b61-4b4e-ba6d-f660dc6af925_861x249.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!B0r3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66850902-3b61-4b4e-ba6d-f660dc6af925_861x249.png" width="861" height="249" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/66850902-3b61-4b4e-ba6d-f660dc6af925_861x249.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:249,&quot;width&quot;:861,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:31396,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/179454478?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66850902-3b61-4b4e-ba6d-f660dc6af925_861x249.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!B0r3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66850902-3b61-4b4e-ba6d-f660dc6af925_861x249.png 424w, https://substackcdn.com/image/fetch/$s_!B0r3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66850902-3b61-4b4e-ba6d-f660dc6af925_861x249.png 848w, https://substackcdn.com/image/fetch/$s_!B0r3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66850902-3b61-4b4e-ba6d-f660dc6af925_861x249.png 1272w, https://substackcdn.com/image/fetch/$s_!B0r3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66850902-3b61-4b4e-ba6d-f660dc6af925_861x249.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>It includes a robust <strong>two-stage GitHub Actions CI/CD pipeline</strong> for validating infrastructure changes on Pull Requests and safely deploying them on merge.</p><p>Two-stage GitHub Actions workflows exist:</p><ol><li><p><strong>Validation Pipeline</strong> (<code>terraform-plan.yml</code>): Runs on Pull Requests (PRs) to validate code and preview changes.</p></li><li><p><strong>Deployment Pipeline</strong> (<code>terraform-apply.yaml</code>): Runs on merges (pushes) to safely deploy validated infrastructure.</p></li></ol><div><hr></div><h3>Stage 1: The PR Validation Pipeline (<code>terraform-plan.yml</code>)</h3><p>This workflow focuses on <strong>pre-deployment validation</strong> and <strong>transparency</strong>. It runs whenever a Pull Request is opened, synced, or reopened against the <code>dev</code>, <code>staging</code>, or <code>main</code> branches.</p><h4>Key Features and Steps:</h4><h4>1. Environment Determination</h4><p>The pipeline determines the target environment based on the PR&#8217;s destination branch (<code>github.base_ref</code>): dev/prod/staging are folder names as well as branch names as wella,each calls terraform module.</p><ul><li><p>If the base branch is <code>main</code>, the environment is set to <code>prod</code>.</p></li><li><p>Otherwise, it uses the branch name (e.g., <code>dev</code> or <code>staging</code>). This is defined by the <code>TF_ENV_FOLDER</code> environment variable.</p></li></ul><h4>2. Secure Authentication with OIDC</h4><p>Instead of long-lived keys, the pipeline uses <strong>OpenID Connect (OIDC)</strong> to assume a secure AWS IAM Role (<code>arn:aws:iam::...:role/GitHubActions-AWS-Admin</code>). This is a security best practice.</p><p>Here is guide how to <a href="https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-aws">set up OIDC</a>, but i&#8217;ll describe it here step by step:</p><p>In AWS console, in IAM click Identity providers-add provider</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BAST!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F970971f2-a26d-4d4a-afea-4a886e199a8e_1903x612.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BAST!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F970971f2-a26d-4d4a-afea-4a886e199a8e_1903x612.png 424w, https://substackcdn.com/image/fetch/$s_!BAST!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F970971f2-a26d-4d4a-afea-4a886e199a8e_1903x612.png 848w, https://substackcdn.com/image/fetch/$s_!BAST!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F970971f2-a26d-4d4a-afea-4a886e199a8e_1903x612.png 1272w, https://substackcdn.com/image/fetch/$s_!BAST!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F970971f2-a26d-4d4a-afea-4a886e199a8e_1903x612.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BAST!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F970971f2-a26d-4d4a-afea-4a886e199a8e_1903x612.png" width="1456" height="468" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/970971f2-a26d-4d4a-afea-4a886e199a8e_1903x612.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:468,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:116559,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/179454478?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F970971f2-a26d-4d4a-afea-4a886e199a8e_1903x612.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BAST!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F970971f2-a26d-4d4a-afea-4a886e199a8e_1903x612.png 424w, https://substackcdn.com/image/fetch/$s_!BAST!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F970971f2-a26d-4d4a-afea-4a886e199a8e_1903x612.png 848w, https://substackcdn.com/image/fetch/$s_!BAST!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F970971f2-a26d-4d4a-afea-4a886e199a8e_1903x612.png 1272w, https://substackcdn.com/image/fetch/$s_!BAST!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F970971f2-a26d-4d4a-afea-4a886e199a8e_1903x612.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Select OpenID connect</p><p>Provider URL: https://token.actions.githubusercontent.com</p><p>Audience: sts.amazonaws.com</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SHgO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F513629f5-3763-4bda-8550-cb90e169c71f_1912x861.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SHgO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F513629f5-3763-4bda-8550-cb90e169c71f_1912x861.png 424w, https://substackcdn.com/image/fetch/$s_!SHgO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F513629f5-3763-4bda-8550-cb90e169c71f_1912x861.png 848w, https://substackcdn.com/image/fetch/$s_!SHgO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F513629f5-3763-4bda-8550-cb90e169c71f_1912x861.png 1272w, https://substackcdn.com/image/fetch/$s_!SHgO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F513629f5-3763-4bda-8550-cb90e169c71f_1912x861.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SHgO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F513629f5-3763-4bda-8550-cb90e169c71f_1912x861.png" width="1456" height="656" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/513629f5-3763-4bda-8550-cb90e169c71f_1912x861.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:656,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:114433,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/179454478?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F513629f5-3763-4bda-8550-cb90e169c71f_1912x861.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!SHgO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F513629f5-3763-4bda-8550-cb90e169c71f_1912x861.png 424w, https://substackcdn.com/image/fetch/$s_!SHgO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F513629f5-3763-4bda-8550-cb90e169c71f_1912x861.png 848w, https://substackcdn.com/image/fetch/$s_!SHgO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F513629f5-3763-4bda-8550-cb90e169c71f_1912x861.png 1272w, https://substackcdn.com/image/fetch/$s_!SHgO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F513629f5-3763-4bda-8550-cb90e169c71f_1912x861.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Click next and click Create role</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dzrw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F232c7cd0-92d8-4a40-b560-e1b851b95691_1892x429.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dzrw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F232c7cd0-92d8-4a40-b560-e1b851b95691_1892x429.png 424w, https://substackcdn.com/image/fetch/$s_!dzrw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F232c7cd0-92d8-4a40-b560-e1b851b95691_1892x429.png 848w, https://substackcdn.com/image/fetch/$s_!dzrw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F232c7cd0-92d8-4a40-b560-e1b851b95691_1892x429.png 1272w, https://substackcdn.com/image/fetch/$s_!dzrw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F232c7cd0-92d8-4a40-b560-e1b851b95691_1892x429.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dzrw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F232c7cd0-92d8-4a40-b560-e1b851b95691_1892x429.png" width="1456" height="330" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/232c7cd0-92d8-4a40-b560-e1b851b95691_1892x429.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:330,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:106830,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/179454478?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F232c7cd0-92d8-4a40-b560-e1b851b95691_1892x429.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dzrw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F232c7cd0-92d8-4a40-b560-e1b851b95691_1892x429.png 424w, https://substackcdn.com/image/fetch/$s_!dzrw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F232c7cd0-92d8-4a40-b560-e1b851b95691_1892x429.png 848w, https://substackcdn.com/image/fetch/$s_!dzrw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F232c7cd0-92d8-4a40-b560-e1b851b95691_1892x429.png 1272w, https://substackcdn.com/image/fetch/$s_!dzrw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F232c7cd0-92d8-4a40-b560-e1b851b95691_1892x429.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>On Trusted entity type page click Web Identity and chose Identity provider, audience, specify Your GitHub organization and GitHub repository</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vNpW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb8590b8-ff7d-44a1-8aa8-9d1c4ede47b0_1900x923.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vNpW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb8590b8-ff7d-44a1-8aa8-9d1c4ede47b0_1900x923.png 424w, https://substackcdn.com/image/fetch/$s_!vNpW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb8590b8-ff7d-44a1-8aa8-9d1c4ede47b0_1900x923.png 848w, https://substackcdn.com/image/fetch/$s_!vNpW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb8590b8-ff7d-44a1-8aa8-9d1c4ede47b0_1900x923.png 1272w, https://substackcdn.com/image/fetch/$s_!vNpW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb8590b8-ff7d-44a1-8aa8-9d1c4ede47b0_1900x923.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vNpW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb8590b8-ff7d-44a1-8aa8-9d1c4ede47b0_1900x923.png" width="1456" height="707" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/db8590b8-ff7d-44a1-8aa8-9d1c4ede47b0_1900x923.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:707,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:150089,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/179454478?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb8590b8-ff7d-44a1-8aa8-9d1c4ede47b0_1900x923.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!vNpW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb8590b8-ff7d-44a1-8aa8-9d1c4ede47b0_1900x923.png 424w, https://substackcdn.com/image/fetch/$s_!vNpW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb8590b8-ff7d-44a1-8aa8-9d1c4ede47b0_1900x923.png 848w, https://substackcdn.com/image/fetch/$s_!vNpW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb8590b8-ff7d-44a1-8aa8-9d1c4ede47b0_1900x923.png 1272w, https://substackcdn.com/image/fetch/$s_!vNpW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb8590b8-ff7d-44a1-8aa8-9d1c4ede47b0_1900x923.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Add administrator role click next, copy Identity ARN, you&#8217;ll need it later on.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gptR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96b2f5c7-3c75-41ad-833f-53bf556c9311_1904x513.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gptR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96b2f5c7-3c75-41ad-833f-53bf556c9311_1904x513.png 424w, https://substackcdn.com/image/fetch/$s_!gptR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96b2f5c7-3c75-41ad-833f-53bf556c9311_1904x513.png 848w, https://substackcdn.com/image/fetch/$s_!gptR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96b2f5c7-3c75-41ad-833f-53bf556c9311_1904x513.png 1272w, https://substackcdn.com/image/fetch/$s_!gptR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96b2f5c7-3c75-41ad-833f-53bf556c9311_1904x513.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gptR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96b2f5c7-3c75-41ad-833f-53bf556c9311_1904x513.png" width="1456" height="392" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/96b2f5c7-3c75-41ad-833f-53bf556c9311_1904x513.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:392,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:97340,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/179454478?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96b2f5c7-3c75-41ad-833f-53bf556c9311_1904x513.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!gptR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96b2f5c7-3c75-41ad-833f-53bf556c9311_1904x513.png 424w, https://substackcdn.com/image/fetch/$s_!gptR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96b2f5c7-3c75-41ad-833f-53bf556c9311_1904x513.png 848w, https://substackcdn.com/image/fetch/$s_!gptR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96b2f5c7-3c75-41ad-833f-53bf556c9311_1904x513.png 1272w, https://substackcdn.com/image/fetch/$s_!gptR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F96b2f5c7-3c75-41ad-833f-53bf556c9311_1904x513.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>In Trusted relationship property of just created role, modify trusted policy to allow this Identity provider to asume this admin role</p><pre><code>{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::12344565:oidc-provider/token.actions.githubusercontent.com"
},
"Action&#8221;: "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringLike": {
"token.actions.githubusercontent.com:sub": [
repo:dragan-actions-course/actions:*",
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
     ]
    }
   }
  }
 ]
}</code></pre><p></p><p><strong>S3 bucket permissions</strong></p><p>I use S3 bucket for terraform TF state, so i created IAM policy, attached to this User entity Role, which allows access to this S3 bucket</p><pre><code>{

    "Version": "2012-10-17",

    "Statement": [

        {

            "Sid": "VisualEditor0",

            "Effect": "Allow",

            "Action": [

                "s3:PutObject",

                "s3:GetObject",

                "s3:ListBucket"

            ],

            "Resource": [

                "arn:aws:s3:::terraform-tfstate-bucket-tatooine",

                "arn:aws:s3:::terraform-tfstate-bucket-tatooine/*"

            ]

        }

    ]

}

</code></pre><p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!iK8o!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b20d87f-8b4d-433d-807a-f76dcf0c8e95_923x706.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!iK8o!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b20d87f-8b4d-433d-807a-f76dcf0c8e95_923x706.png 424w, https://substackcdn.com/image/fetch/$s_!iK8o!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b20d87f-8b4d-433d-807a-f76dcf0c8e95_923x706.png 848w, https://substackcdn.com/image/fetch/$s_!iK8o!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b20d87f-8b4d-433d-807a-f76dcf0c8e95_923x706.png 1272w, https://substackcdn.com/image/fetch/$s_!iK8o!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b20d87f-8b4d-433d-807a-f76dcf0c8e95_923x706.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!iK8o!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b20d87f-8b4d-433d-807a-f76dcf0c8e95_923x706.png" width="923" height="706" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6b20d87f-8b4d-433d-807a-f76dcf0c8e95_923x706.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:706,&quot;width&quot;:923,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:71432,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/179454478?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b20d87f-8b4d-433d-807a-f76dcf0c8e95_923x706.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!iK8o!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b20d87f-8b4d-433d-807a-f76dcf0c8e95_923x706.png 424w, https://substackcdn.com/image/fetch/$s_!iK8o!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b20d87f-8b4d-433d-807a-f76dcf0c8e95_923x706.png 848w, https://substackcdn.com/image/fetch/$s_!iK8o!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b20d87f-8b4d-433d-807a-f76dcf0c8e95_923x706.png 1272w, https://substackcdn.com/image/fetch/$s_!iK8o!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b20d87f-8b4d-433d-807a-f76dcf0c8e95_923x706.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Now Managed Identity,when called by GitHub actions workflow, assumes Admin role and have access to S3 bucket to store Terraform state.</p><p> </p><h4>3. The Core Validation: Terraform Plan</h4><p>The job executes a Python wrapper (<code>tf_wrapper.py</code>) to run <code>terraform plan</code> for the calculated environment folder (e.g., <code>environments/staging</code>).</p><ul><li><p>It captures the full output and the exit code.</p></li><li><p>The job <strong>fails</strong> only if the exit code is <code>1</code> (indicating a hard configuration error), ensuring bad code doesn&#8217;t proceed.</p></li></ul><h4>4. Pull Request Visibility</h4><p>The captured plan output is automatically posted back as a <strong>comment</strong> on the Pull Request. This gives reviewers an immediate, transparent view of exactly what infrastructure changes will occur if the code is merged.</p><h4>5. Static Code Analysis</h4><p>To catch issues before deployment, the workflow runs static analysis tools:</p><ul><li><p><strong>TFLint</strong>: Ensures adherence to style and module structure.</p></li><li><p><strong>Checkov</strong>: Performs security scanning on the Terraform code, flagging potential misconfigurations.</p></li><li><p>The raw JSON and a converted <strong>HTML report</strong> from Checkov are saved as artifacts for review.</p></li></ul><div><hr></div><h3>Stage 2: The Deployment Pipeline (<code>terraform-apply.yaml</code>)</h3><p>This workflow is the <strong>gatekeeper</strong> for deployment. It only runs on a <code>push</code> event (i.e., when code is merged) to the <code>dev</code>, <code>staging</code>, or <code>main</code> branches.</p><h4>Key Features and Steps:</h4><h4>1. Environment and Concurrency Control</h4><p>Similar to the plan, the environment is determined using the branch name (<code>github.ref_name</code>), mapping <code>main</code> to <code>prod</code>. Crucially, the <strong>concurrency group</strong> is set using the branch name, ensuring that only <strong>one deployment</strong> to a specific environment (e.g., <code>staging</code>) can run at any given time. This prevents race conditions and state file corruption.</p><h4>2. Deployment Notification</h4><p>Before execution, a <strong>commit comment</strong> is posted with the deployment start time and status. This provides immediate feedback to the team on the merge commit itself.</p><h4>3. The Core Deployment: Terraform Apply</h4><p>The workflow uses the Python wrapper to execute the full Terraform workflow (init, plan, and apply) for the specified environment.</p><ul><li><p>The <code>TF_VAR_environment</code> variable is explicitly passed to allow modules to tag resources with the correct environment name (e.g., <code>dev</code>, <code>staging</code>, or <code>prod</code>). So it pickups names of folders in GitHub repository</p></li><li><p>Exit codes <code>0</code> (no changes) and <code>2</code> (changes applied) are considered <strong>successes</strong>.</p></li><li><p>Only exit code <code>1</code> triggers a critical failure and stops the deployment.</p></li></ul><p></p><h3>Transparency on Pull Requests (The Validation Stage)</h3><p>The primary goal of the <strong>Validation Pipeline</strong> (<code>terraform-plan.yml</code>) is to ensure every reviewer understands the precise impact of the code changes before they are merged.</p><ul><li><p><strong>Automatic Plan Output:</strong> When a Pull Request is opened or updated, the workflow automatically executes the <code>terraform plan</code>. It captures the full output, which details exactly what AWS resources will be created, updated, or destroyed.</p></li><li><p><strong>PR Comment:</strong> The pipeline then posts this captured output as a detailed <strong>comment</strong> directly on the Pull Request. This means reviewers don&#8217;t have to leave the PR page or dig through CI logs; the critical decision-making information is right there.</p></li></ul><p>This transparency helps answer the crucial question: &#8220;What is this change actually doing?&#8221; with an unalterable, machine-generated report.</p><h3>Notifications on Merge (The Deployment Stage)</h3><p>Once the code is approved and merged, the <strong>Deployment Pipeline</strong> (<code>terraform-apply.yaml</code>) takes over, focusing on keeping the team updated on the deployment status.</p><ul><li><p><strong>Deployment Start Notification:</strong> As soon as the merge triggers the deployment workflow, the pipeline posts a <strong>commit comment</strong> on the merge commit. This comment provides immediate notification that the infrastructure update has begun, including the start time and the target environment (e.g., <code>DEV</code>, <code>STAGING</code>, or <code>PROD</code>).</p></li><li><p><strong>Status Tracking:</strong> This initial notification acts as an easy-to-find marker, allowing team members to monitor the job&#8217;s progress directly via a link to the workflow run.</p></li></ul><h2>The Terraform Python Wrapper (<code>tf_wrapper.py</code>)</h2><p>While GitHub Actions provides the environment, the <strong><a href="https://github.com/dragan1979/aws-githhub-actions/blob/main/tf_wrapper.py">Python wrapper script</a></strong><a href="https://github.com/dragan1979/aws-githhub-actions/blob/main/tf_wrapper.py"> (</a><code>tf_wrapper.py</code><a href="https://github.com/dragan1979/aws-githhub-actions/blob/main/tf_wrapper.py">)</a> is the true orchestrator that manages the multi-step execution of Terraform commands within that environment.</p><p>This wrapper is primarily designed to enforce a consistent workflow and handle the tricky logic of capturing output and managing exit codes.</p><h3>How the Wrapper Executes Terraform</h3><p>The Python script does not run the Terraform logic itself; instead, it uses Python&#8217;s <code>subprocess</code> module to execute the native <strong>Terraform CLI binary</strong> on the runner machine.</p><p>The execution flow within <code>tf_wrapper.py</code> for a deployment or plan is a simple but powerful sequence:</p><h4>Argument Parsing and Environment Setup</h4><p>The wrapper first accepts the target environment path (e.g., <code>environments/staging</code>) as an argument from the GitHub Action:</p><ul><li><p>It changes the current working directory (<code>cd</code>) to this environment folder. All subsequent Terraform commands run relative to this path, ensuring the correct configuration files (<code>.tf</code>) and state are used.</p></li></ul><h2>The Python Utility Script (<code>convert_json_to_html.py</code>)</h2><p><a href="https://github.com/dragan1979/aws-githhub-actions/blob/main/convert_json_to_html.py">This Python script</a> is a utility run during the <code>terraform-plan.yml</code> CI workflow to improve the usability of the security audit results.</p><ul><li><p>The script&#8217;s sole function is to read the raw <strong>JSON output</strong> generated by the Checkov security scanner and convert it into a styled, self-contained <strong>HTML report</strong>. This makes the security findings easy to review directly in a browser without needing to parse complex JSON data.</p></li><li><p>It leverages the <strong>Jinja2</strong> templating library to process the JSON data into a defined <code>HTML_TEMPLATE</code>.</p></li><li><p>The script extracts and formats the following key information from the Checkov JSON:</p><ul><li><p><strong>Summary:</strong> Total number of failed, passed, and skipped checks.</p></li><li><p><strong>Failed Checks Details:</strong> For every failed security rule, it lists the <code>Check ID</code>, <code>Check Name</code>, the offending <code>File Path</code>, the specific <code>Resource</code> (e.g., <code>aws_vpc.main</code>), and the line number of the violation.</p></li></ul></li></ul><p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YZrP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3233e081-2734-4e9a-bd8c-c2a2c5d8585e_1873x864.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YZrP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3233e081-2734-4e9a-bd8c-c2a2c5d8585e_1873x864.png 424w, https://substackcdn.com/image/fetch/$s_!YZrP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3233e081-2734-4e9a-bd8c-c2a2c5d8585e_1873x864.png 848w, https://substackcdn.com/image/fetch/$s_!YZrP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3233e081-2734-4e9a-bd8c-c2a2c5d8585e_1873x864.png 1272w, https://substackcdn.com/image/fetch/$s_!YZrP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3233e081-2734-4e9a-bd8c-c2a2c5d8585e_1873x864.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YZrP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3233e081-2734-4e9a-bd8c-c2a2c5d8585e_1873x864.png" width="1456" height="672" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3233e081-2734-4e9a-bd8c-c2a2c5d8585e_1873x864.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:672,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:102052,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/179454478?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3233e081-2734-4e9a-bd8c-c2a2c5d8585e_1873x864.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!YZrP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3233e081-2734-4e9a-bd8c-c2a2c5d8585e_1873x864.png 424w, https://substackcdn.com/image/fetch/$s_!YZrP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3233e081-2734-4e9a-bd8c-c2a2c5d8585e_1873x864.png 848w, https://substackcdn.com/image/fetch/$s_!YZrP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3233e081-2734-4e9a-bd8c-c2a2c5d8585e_1873x864.png 1272w, https://substackcdn.com/image/fetch/$s_!YZrP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3233e081-2734-4e9a-bd8c-c2a2c5d8585e_1873x864.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Complete code is available <a href="https://github.com/dragan1979/aws-githhub-actions">here</a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/automating-terraform-aws-deployment?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/automating-terraform-aws-deployment?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/automating-terraform-aws-deployment/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/automating-terraform-aws-deployment/comments"><span>Leave a comment</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Automating Windows Active directory/Domain Controller Setup with PowerShell]]></title><description><![CDATA[This script is structured into several steps and uses a robust function set for logging and state management.]]></description><link>https://adminjournal.substack.com/p/automating-windows-active-directorydc</link><guid isPermaLink="false">https://adminjournal.substack.com/p/automating-windows-active-directorydc</guid><dc:creator><![CDATA[Драган Вучановић]]></dc:creator><pubDate>Sun, 09 Nov 2025 12:11:54 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!VVr5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95ec7e6c-3077-4150-8a70-992ae9135761_1102x814.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VVr5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95ec7e6c-3077-4150-8a70-992ae9135761_1102x814.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VVr5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95ec7e6c-3077-4150-8a70-992ae9135761_1102x814.png 424w, https://substackcdn.com/image/fetch/$s_!VVr5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95ec7e6c-3077-4150-8a70-992ae9135761_1102x814.png 848w, https://substackcdn.com/image/fetch/$s_!VVr5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95ec7e6c-3077-4150-8a70-992ae9135761_1102x814.png 1272w, https://substackcdn.com/image/fetch/$s_!VVr5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95ec7e6c-3077-4150-8a70-992ae9135761_1102x814.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VVr5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95ec7e6c-3077-4150-8a70-992ae9135761_1102x814.png" width="1102" height="814" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/95ec7e6c-3077-4150-8a70-992ae9135761_1102x814.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:814,&quot;width&quot;:1102,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1124886,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/178408573?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95ec7e6c-3077-4150-8a70-992ae9135761_1102x814.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!VVr5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95ec7e6c-3077-4150-8a70-992ae9135761_1102x814.png 424w, https://substackcdn.com/image/fetch/$s_!VVr5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95ec7e6c-3077-4150-8a70-992ae9135761_1102x814.png 848w, https://substackcdn.com/image/fetch/$s_!VVr5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95ec7e6c-3077-4150-8a70-992ae9135761_1102x814.png 1272w, https://substackcdn.com/image/fetch/$s_!VVr5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F95ec7e6c-3077-4150-8a70-992ae9135761_1102x814.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This script is structured into several steps and uses a robust function set for logging and state management.</p><h4>Resumable Execution via State Management</h4><p>This script ensures that you can run it, reboot when necessary, and the script will pick up <em>exactly</em> where it left off, making DC provisioning repeatable and reliable.</p><p>The core of this script&#8217;s reliability is the <code>Get-ScriptState</code> and <code>Set-ScriptState</code> functions.</p><p><strong>State File (</strong><code>C:\Logs\state.json</code><strong>)</strong>: Before a mandatory reboot (like after server rename or AD promotion), the script saves its <strong>current step number</strong> and <strong>all essential parameters</strong> (like <code>$DomainName</code>, <code>$DSRMPassword</code>, etc.) to a JSON file.</p><p>The <code>Set-ScheduledTask</code> function creates a task (<code>DCSetupTask</code>) that executes the script <strong>at startup</strong>. This is critical for catching the script execution immediately after the server reboots following the rename or DC promotion. Once the script is complete, the <code>Remove-ScheduledTask</code> function cleans up the environment.</p><p>The script uses a sequential flow controlled by the <code>$State.CurrentStep</code> variable. Crucially, each step includes checks to ensure it only performs an action if necessary (<strong>idempotency</strong>):</p><p><strong>Rename Server</strong></p><p>Checks <code>$env:COMPUTERNAME -ne $ServerName</code>. If successful, it sets the scheduled task and reboots.</p><p><strong>Install AD DS &amp; Promote</strong></p><p>Checks if the <code>AD-Domain-Services</code> feature is installed and if the server is already a DC for the target domain.</p><p><strong>Create AD Objects</strong></p><p><strong>Polls</strong> until the Active Directory is fully ready. Creates required OUs (<code>TestUsers</code>, <code>Groups</code>, <code>Servers</code>) only if they don&#8217;t exist. Creates standard users and a dedicated administrator (<code>adm-setup</code>) and adds the admin to <strong>Domain Admins.</strong></p><p><strong>Install &amp; Configure IIS</strong></p><p>Checks if IIS features are installed and only creates the default <code>index.html</code> if it doesn&#8217;t exist. It also ensures the &#8220;Default Web Site&#8221; is started.</p><pre><code>param(
    [Parameter(Mandatory=$true)]
    [string]$DomainName,
    [Parameter(Mandatory=$true)]
    [string]$DSRMPassword,
    [Parameter(Mandatory=$true)]
    [string]$DefaultUserPassword,
    [string]$ServerName,
    [string]$AdminUsername = "adm-setup" 
)


# 1. General Variables
$ScriptPath = $MyInvocation.MyCommand.Path
$LogFilePath = "C:\Logs\build.log"
$StateFilePath = "C:\Logs\state.json"
$TaskName = "DCSetupTask" # Used by Set/Remove-ScheduledTask

# Ensure Logs directory exists
if (-not (Test-Path "C:\Logs")) {
    New-Item -Path "C:\Logs" -ItemType Directory | Out-Null
}

# Functions for Logging and State Management
function Write-Log {
    param(
        [Parameter(Mandatory=$true)]
        [string]$Message,
        [Parameter(Mandatory=$false)]
        [string]$Level = "INFO" # INFO, WARN, ERROR
    )
    $Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $LogEntry = "[$Timestamp] [$Level] $Message"
    Add-Content -Path $LogFilePath -Value $LogEntry
    Write-Host &#8220;$LogEntry&#8221;
}

function Get-ScriptState {
       
    if (Test-Path $StateFilePath) {
       
        try {
            Write-Host "Found state file. Resuming setup."
            $State = Get-Content $StateFilePath | ConvertFrom-Json
            # Add default values if missing
            if (-not $State.CurrentStep) { $State.CurrentStep = 1 }
            if (-not $State.RebootPending) { $State.RebootPending = $false }
            return $State
        } catch {
            Write-Host "WARNING: State file was found but appears corrupt. Starting fresh." -ForegroundColor Yellow
        }
    }
    
    # If Test-Path was false, OR if the try block failed, return the Initial state
    Write-Host "No valid state file found. Starting fresh setup."
    return [PSCustomObject]@{
        CurrentStep = 1
        RebootPending = $false
        DomainName = $DomainName
        DSRMPassword = $DSRMPassword
        DefaultUserPassword = $DefaultUserPassword
        ServerName = $ServerName
    }
}

function Set-ScriptState {
    param(
        [Parameter(Mandatory=$true)]
        [PSCustomObject]$State
    )
    $State | ConvertTo-Json -Depth 5 | Out-File $StateFilePath -Force
}

function Set-ScheduledTask {
    param(
        [Parameter(Mandatory=$true)]
        [string]$PathToScript,
        [Parameter(Mandatory=$true)]
        [string]$DomainName,
        [Parameter(Mandatory=$true)]
        [string]$DSRMPassword,
        [Parameter(Mandatory=$true)]
        [string]$DefaultUserPassword,
        [Parameter(Mandatory=$true)]
        [string]$ServerName
    )
    Write-Log "Creating scheduled task '$TaskName' for self-resumption after reboot."
    
    # Construct arguments string for the scheduled task
    $Arguments = "-ExecutionPolicy Bypass -File `"$PathToScript`" -DomainName `"$DomainName`" -DSRMPassword `"$DSRMPassword`" -DefaultUserPassword `"$DefaultUserPassword`" -ServerName `"$ServerName`""

    $Action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument $Arguments
    $Trigger = New-ScheduledTaskTrigger -AtStartup
    $Settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -StartWhenAvailable
    
    Register-ScheduledTask -TaskName $TaskName -Action $Action -Trigger $Trigger -Settings $Settings -User &#8220;System&#8221; -Force | Out-Null
    Write-Log "Scheduled task created. The script will resume automatically."
}

function Remove-ScheduledTask {
    if (Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue) {
        Write-Log "Removing scheduled task '$TaskName'."
        Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false
    }
}


Write-Log "--- Starting DC Setup Script ---"

$State = Get-ScriptState

# Override initial parameters if we are resuming
if ($State.CurrentStep -gt 1) {
    Write-Log "Resuming from state: Step $($State.CurrentStep)" -Level "WARN"
    $DomainName = $State.DomainName
    $DSRMPassword = $State.DSRMPassword
    $DefaultUserPassword = $State.DefaultUserPassword
    $ServerName = $State.ServerName
    # If the state indicates reboot is pending, and we&#8217;ve just booted, we&#8217;ve successfully rebooted.
    if ($State.RebootPending -eq $true) {
        $State.RebootPending = $false
        $State.CurrentStep = 3 # Skip steps 1 (Rename) and 2 (DC Promo/Reboot)
        Set-ScriptState -State $State
    }
}

# Rename Server to DC01 (If necessary)
if ($State.CurrentStep -eq 1) {
    Write-Log "Step 1: Renaming server to $ServerName."

    if ($env:COMPUTERNAME -ne $ServerName) {
        Write-Log &#8220;Current name is '$($env:COMPUTERNAME)'. Renaming to '$ServerName'."

        try {
            # Attempt the rename operation
            Rename-Computer -NewName $ServerName -Force -ErrorAction Stop

            # If rename succeeds, prepare for reboot
            $State.RebootPending = $true
            $State.CurrentStep = 1
            Set-ScriptState -State $State
            Set-ScheduledTask -PathToScript $ScriptPath -DomainName $DomainName -DSRMPassword $DSRMPassword -DefaultUserPassword $DefaultUserPassword -ServerName $ServerName
            Write-Log "Server renamed successfully. Initiating reboot now..." -Level "WARN"
            Restart-Computer -Force
            exit # Wait for reboot

        } catch {
            $ErrorMessage = "Failed to rename the server: $($_.Exception.Message)"
            Write-Log &#8220;FATAL ERROR: $ErrorMessage. Setting state to 99 and exiting.&#8221; -Level "ERROR"

            # Set state to 99 (Error State)
            $State.CurrentStep = 99
            Set-ScriptState -State $State

            # Write a standard PowerShell error and exit the script
            Write-Error -Message $ErrorMessage -ErrorAction Stop
            exit 1 
        }
    } else {
        Write-Log "Server already named &#8216;$ServerName&#8217;. Skipping rename."
        $State.CurrentStep = 2
        Set-ScriptState -State $State
    }
}

# Install AD DS and Promote to DC
if ($State.CurrentStep -eq 2) {
    Write-Log "Step 2: Installing AD DS Role and promoting to DC."
    
    # Check if AD DS is already installed
    if ((Get-WindowsFeature AD-Domain-Services).Installed -eq $false) {
        Write-Log "Installing AD-Domain-Services feature."
        Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools -Confirm:$false -Restart:$false | Out-Null
    } else {
        Write-Log "AD-Domain-Services feature already installed."
    }

    # Check if we are already a DC by testing for AD domain existence
    $IsDC = $false
    try {
        $Domain = Get-ADDomain -ErrorAction Stop
        if ($Domain.DNSRoot -eq $DomainName) {
            $IsDC = $true
        }
    } catch {
        # AD Domain cmdlets not available or domain doesn&#8217;t exist yet
        Write-Log "AD Domain not yet configured. Proceeding with promotion."
    }

    if (-not $IsDC) {
        $SafeModePassword = ConvertTo-SecureString $DSRMPassword -AsPlainText -Force
        
        Write-Log &#8220;Promoting server to a Domain Controller for new forest '$DomainName'."
        
        try {
            Install-ADDSForest `
                -CreateDnsDelegation:$false `
                -DatabasePath "C:\Windows\NTDS" `
                -DomainName $DomainName `
                -DomainMode "WinThreshold" `
                -DomainNetbiosName $DomainName.Split('.')[0].ToUpper() `
                -ForestMode "WinThreshold" `
                -LogPath "C:\Windows\NTDS" `
                -NoRebootOnCompletion:$false `
                -SYSVOLPath "C:\Windows\SYSVOL" `
                -Force:$true `
                -InstallDns:$true `
                -SafeModeAdministratorPassword $SafeModePassword `
                -ErrorAction Stop
            
            # If we reach here, promotion initiated successfully
            $State.RebootPending = $true
            $State.CurrentStep = 2
            Set-ScriptState -State $State
            Write-Log "AD DS promotion initiated. Waiting for automatic reboot..." -Level "WARN"
            exit # Wait for automatic reboot by Install-ADDSForest
            
        } catch {
            $ErrorMessage = "Failed to promote server to DC: $($_.Exception.Message)"
            Write-Log &#8220;FATAL ERROR: $ErrorMessage&#8221; -Level "ERROR"
            $State.CurrentStep = 99
            Set-ScriptState -State $State
            Write-Error -Message $ErrorMessage -ErrorAction Stop
            exit 1
        }
    } else {
        Write-Log "Server is already a DC for '$DomainName'. Skipping promotion."
        $State.CurrentStep = 3
        Set-ScriptState -State $State
    }
}

# Create OUs, Users, and Admin User (Requires AD DS to be fully functional)
if ($State.CurrentStep -eq 3) {
    Write-Log "Step 3: Creating AD OUs and Users."

    try {
        Import-Module ActiveDirectory -ErrorAction Stop
    } catch {
        Write-Log "FATAL ERROR: Could not import ActiveDirectory module. Is the feature installed?" -Level &#8220;ERROR&#8221;
        $State.CurrentStep = 99
        Set-ScriptState -State $State
        exit 1
    }
    
    $MaxAttempts = 700 # Check for 700 seconds
    $Attempt = 0
    $ADReady = $false
    $BaseDN = $null
    
    Write-Log "Polling for Active Directory Domain Services readiness (Max 120 seconds)..."
    
    while (-not $ADReady -and $Attempt -lt $MaxAttempts) {
        try {
            $BaseDN = (Get-ADDomain -ErrorAction Stop).DistinguishedName
            $ADReady = $true
        } catch {
            $Attempt++
            Write-Log "Attempt $Attempt/$MaxAttempts AD DS not ready. Waiting 2 seconds..." -Level "WARN"
            Start-Sleep -Seconds 2
        }
    }
    
    if (-not $ADReady) {
        $ErrorMessage = "AD DS did not become ready after $($MaxAttempts*2) seconds. Cannot proceed to create OUs/Users."
        Write-Log "FATAL ERROR: $ErrorMessage. Setting state to 99 and exiting." -Level "ERROR"
        $State.CurrentStep = 99
        Set-ScriptState -State $State
        Write-Error -Message $ErrorMessage -ErrorAction Stop
        exit 1
    }
    Write-Log "Active Directory is ready. Proceeding with OU and User creation."
    
    # Create OUs
    Write-Log "Creating required Organizational Units."
    $OUs = @("TestUsers", "Groups", "Servers")
    
    foreach ($OUName in $OUs) {
        $OUPath = "OU=$OUName,$BaseDN"
        
        
        $OUExists = $false
        try {
            $null = Get-ADOrganizationalUnit -Identity $OUPath -ErrorAction Stop
            $OUExists = $true
        } catch {
            # OU doesn&#8217;t exist, we&#8217;ll create it
        }
        
        if (-not $OUExists) {
            Write-Log "Creating OU: $OUName"
            New-ADOrganizationalUnit -Name $OUName -Path $BaseDN -ProtectedFromAccidentalDeletion $true
        } else {
            Write-Log "OU '$OUName' already exists."
        }
    }
    
    # Create Standard Users
    Write-Log "Creating standard users."
    $PasswordSecure = ConvertTo-SecureString $DefaultUserPassword -AsPlainText -Force
    $UserCounter = 1
    
    foreach ($OUName in $OUs) {
        $OUPath = "OU=$OUName,$BaseDN"
        for ($i = 1; $i -le 3; $i++) {
            $UserName = "stduser$UserCounter"
            
            $UserExists = $false
            try {
                $null = Get-ADUser -Identity $UserName -ErrorAction Stop
                $UserExists = $true
            } catch {
                # User doesn&#8217;t exist, we&#8217;ll create it
            }
            
            if (-not $UserExists) {
                Write-Log "Creating standard user: $UserName in OU '$OUName'."
                New-ADUser -Name $UserName -GivenName "Standard" -Surname "User$UserCounter" -SamAccountName $UserName `
                    -UserPrincipalName "$UserName@$DomainName" -Path $OUPath `
                    -AccountPassword $PasswordSecure -Enabled $true `
                    -ChangePasswordAtLogon $false
                # Set password to never expire
                Set-ADAccountControl -Identity $UserName -PasswordNeverExpires $true
            } else {
                Write-Log "Standard user '$UserName' already exists."
            }
            $UserCounter++
        }
    }
    
    # 3c: Create Domain Admin User
    Write-Log "Creating dedicated Domain Administrator user '$AdminUsername'."
    
    # Use try-catch to completely suppress error output
    $AdminExists = $false
    try {
        $null = Get-ADUser -Identity $AdminUsername -ErrorAction Stop
        $AdminExists = $true
    } catch {
        # Admin doesn&#8217;t exist, we&#8217;ll create it
    }
    
    if (-not $AdminExists) {
        New-ADUser -Name $AdminUsername -GivenName "Setup" -Surname "Admin" -SamAccountName $AdminUsername `
            -UserPrincipalName "$AdminUsername@$DomainName" -Path "OU=TestUsers,$BaseDN" `
            -AccountPassword $PasswordSecure -Enabled $true `
            -ChangePasswordAtLogon $false
            
        # Add to Domain Admins group
        Add-ADGroupMember -Identity "Domain Admins" -Members $AdminUsername
        Set-ADAccountControl -Identity $AdminUsername -PasswordNeverExpires $true
        Write-Log "Domain Admin user '$AdminUsername' created and added to 'Domain Admins'."
    } else {
        Write-Log "Domain Admin user '$AdminUsername' already exists.&#8221;
    }

    $State.CurrentStep = 4
    Set-ScriptState -State $State
}

# STEP 4: Install IIS and Configure Landing Page
if ($State.CurrentStep -eq 4) {
    Write-Log "Step 4: Installing IIS Web-Server role and configuring landing page."

    try {
        # Install IIS (Web-Server and Management Tools)
        $IISFeatures = @("Web-Server", "Web-Mgmt-Tools")
        foreach ($Feature in $IISFeatures) {
            if ((Get-WindowsFeature $Feature).Installed -eq $false) {
                Write-Log &#8220;Installing Windows Feature: $Feature&#8221;
               Install-WindowsFeature -Name $Feature -Confirm:$false -Restart:$false -ErrorAction Stop | Out-Null
            } else {
                Write-Log "Windows Feature '$Feature' already installed."
            }
        }
        
        # Check if the site is already running 
        $SitePath = "C:\inetpub\wwwroot\index.html"
        $SiteContent = "&lt;html&gt;&lt;body&gt;&lt;h1&gt;Hello World from Server!&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;"
        
        # Configure Landing Page
     
        if (-not (Test-Path $SitePath)) {
            Write-Log "Creating default $SitePath with a simple landing page."
            $SiteContent | Out-File $SitePath -Encoding UTF8 -Force -ErrorAction Stop
        } else {
            Write-Log "Landing page $SitePath already exists. Skipping replacement."
        }
        
        # Ensure Default Site is Started and Listening on Port 80
        Write-Log "Ensuring Default Web Site is started."
        $DefaultSite = Get-Website -Name "Default Web Site" -ErrorAction SilentlyContinue
        if (-not $DefaultSite) {
            throw "Default Web Site does not exist after IIS installation."
        }

        if ($DefaultSite.State -ne "Started") {
            Start-Website -Name "Default Web Site" -ErrorAction Stop
        } else {
            Write-Log "Default Web Site is already started."
        }

        $State.CurrentStep = 5
        Set-ScriptState -State $State
        Write-Log "IIS installation and configuration completed successfully."

    } catch {
        $ErrorMessage = "Failed during IIS installation or configuration: $($_.Exception.Message)"
        Write-Log "FATAL ERROR: $ErrorMessage. Setting state to 99 and exiting." -Level "ERROR"

        # Set state to 99 (Error State)
        $State.CurrentStep = 99
        Set-ScriptState -State $State

        # Write a standard PowerShell error and exit the script
        Write-Error -Message $ErrorMessage -ErrorAction Stop
        exit 1
    }
}

# Finalization and Cleanup
if ($State.CurrentStep -eq 5) {
    Write-Log "Step 5: Finalization and Cleanup."

    # Remove the state file
    Remove-Item -Path $StateFilePath -Force -ErrorAction SilentlyContinue
    # Ensure the scheduled task is removed
    Remove-ScheduledTask

    Write-Log "--- Script Complete! DC01 setup is finished. ---"
}</code></pre><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/automating-windows-active-directorydc?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/automating-windows-active-directorydc?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/automating-windows-active-directorydc/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/automating-windows-active-directorydc/comments"><span>Leave a comment</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Backup and Restore Azure Kubernetes Service Cluster - AKS]]></title><link>https://adminjournal.substack.com/p/backup-and-restore-azure-kubernetes</link><guid isPermaLink="false">https://adminjournal.substack.com/p/backup-and-restore-azure-kubernetes</guid><dc:creator><![CDATA[Драган Вучановић]]></dc:creator><pubDate>Tue, 04 Nov 2025 15:24:00 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!uczE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23c70929-24d5-403a-9d1b-0e35c8f2ae3f_1169x613.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uczE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23c70929-24d5-403a-9d1b-0e35c8f2ae3f_1169x613.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uczE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23c70929-24d5-403a-9d1b-0e35c8f2ae3f_1169x613.png 424w, https://substackcdn.com/image/fetch/$s_!uczE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23c70929-24d5-403a-9d1b-0e35c8f2ae3f_1169x613.png 848w, https://substackcdn.com/image/fetch/$s_!uczE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23c70929-24d5-403a-9d1b-0e35c8f2ae3f_1169x613.png 1272w, https://substackcdn.com/image/fetch/$s_!uczE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23c70929-24d5-403a-9d1b-0e35c8f2ae3f_1169x613.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uczE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23c70929-24d5-403a-9d1b-0e35c8f2ae3f_1169x613.png" width="1169" height="613" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/23c70929-24d5-403a-9d1b-0e35c8f2ae3f_1169x613.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:613,&quot;width&quot;:1169,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:365269,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/177977073?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23c70929-24d5-403a-9d1b-0e35c8f2ae3f_1169x613.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!uczE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23c70929-24d5-403a-9d1b-0e35c8f2ae3f_1169x613.png 424w, https://substackcdn.com/image/fetch/$s_!uczE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23c70929-24d5-403a-9d1b-0e35c8f2ae3f_1169x613.png 848w, https://substackcdn.com/image/fetch/$s_!uczE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23c70929-24d5-403a-9d1b-0e35c8f2ae3f_1169x613.png 1272w, https://substackcdn.com/image/fetch/$s_!uczE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F23c70929-24d5-403a-9d1b-0e35c8f2ae3f_1169x613.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>While Microsoft handles the underlying infrastructure and control plane (like the etcd database for the cluster state), <strong>Azure customares</strong> are responsible for protecting:</p><ul><li><p><strong>Application Data:</strong> The persistent volumes (PVs) and persistent volume claims (PVCs) that store the vital data for your stateful applications (databases, message queues, file storage).</p></li><li><p><strong>Cluster Resources:</strong> The key configuration elements, like Deployments, Services, ConfigMaps, and Secrets, that define how your application runs.</p></li></ul><p>Without a solid backup, a simple misconfiguration, an accidental deletion, or a broader regional disaster could lead to <strong>significant data loss</strong> and <strong>extended downtime</strong>, impacting business continuity and hitting your bottom line.</p><p>This post will explore how to implement a <strong>cloud-native, application-aware backup and restore solution</strong> for your AKS clusters, focusing on solutions like <strong>Azure Backup for AKS.</strong></p><p>Azure Backup for AKS <strong>DOES NOT</strong> backup:</p><ul><li><p><strong>The Kubernetes Control Plane Software:</strong> The version of the core Kubernetes components (like the API server, scheduler, and controller manager) running your cluster. This is entirely managed by the AKS service.</p></li><li><p><strong>The Operating System (OS) Image:</strong> The underlying OS image (e.g., Ubuntu or Windows Server) used by your node pool VMs.</p></li><li><p><strong>Networking Configuration:</strong> Virtual Networks, Subnets, Load Balancer rules external to the cluster, etc.</p></li></ul><p>Azure Backup captures the state and data <strong>defined by the running version</strong>:</p><ul><li><p><strong>Cluster State (etcd data equivalent):</strong> All the Kubernetes API resources (the YAML manifests) like Deployments, Services, ConfigMaps, Secrets, RBAC roles, and PVCs.</p></li><li><p><strong>Persistent Data:</strong> Snapshots of the underlying Azure Disks (Persistent Volumes) used by your stateful applications.</p></li></ul><p></p><p>Required roles:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Jma9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e57e9e0-2a27-47e7-92d2-e9eb50166412_676x685.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Jma9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e57e9e0-2a27-47e7-92d2-e9eb50166412_676x685.png 424w, https://substackcdn.com/image/fetch/$s_!Jma9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e57e9e0-2a27-47e7-92d2-e9eb50166412_676x685.png 848w, https://substackcdn.com/image/fetch/$s_!Jma9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e57e9e0-2a27-47e7-92d2-e9eb50166412_676x685.png 1272w, https://substackcdn.com/image/fetch/$s_!Jma9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e57e9e0-2a27-47e7-92d2-e9eb50166412_676x685.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Jma9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e57e9e0-2a27-47e7-92d2-e9eb50166412_676x685.png" width="676" height="685" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8e57e9e0-2a27-47e7-92d2-e9eb50166412_676x685.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:685,&quot;width&quot;:676,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:45849,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/177977073?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e57e9e0-2a27-47e7-92d2-e9eb50166412_676x685.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Jma9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e57e9e0-2a27-47e7-92d2-e9eb50166412_676x685.png 424w, https://substackcdn.com/image/fetch/$s_!Jma9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e57e9e0-2a27-47e7-92d2-e9eb50166412_676x685.png 848w, https://substackcdn.com/image/fetch/$s_!Jma9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e57e9e0-2a27-47e7-92d2-e9eb50166412_676x685.png 1272w, https://substackcdn.com/image/fetch/$s_!Jma9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e57e9e0-2a27-47e7-92d2-e9eb50166412_676x685.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Below is code for creating Storage acocunt,Blob container,Key vault,permissions/roles needed for Azure backup and Resource group for storing backup snapshot.</p><pre><code>$RESOURCE_GROUP="aks"
$CLUSTER_NAME="myaks"
$Location="westeurope"


# Create snapshot resource group
$SNAPSHOT_RG_NAME="snapshot-rg"
az group create `
  --name $SNAPSHOT_RG_NAME `
  --location $Location

# Check the status of your CSI driver. The required add-on is azurekeyvaultkms
az aks show --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME --query "storageProfile.diskCsiDriver.enabled"
# If not enabled, enable it using the following command:
az aks update --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME --enable-disk-csi-driver

# Register the necessary resource provider for the Backup Extension.
az provider register --namespace Microsoft.KubernetesConfiguration
az provider register --namespace Microsoft.ContainerService 

$backupVaultRG="backup-vault"
$vaultName="MyAKSBackupVault"
$blobContainerName="aks-backup-container"

az group create `
  --name $backupVaultRG  `
  --location $Location

# Configure the CLI to automatically install extensions without asking
az config set extension.use_dynamic_install=yes_without_prompt

az dataprotection backup-vault create `
  --resource-group $backupVaultRG `
  --vault-name $vaultName `
  --location $Location `
  --type SystemAssigned `
  --storage-settings type="LocallyRedundant" datastore-type="VaultStore"
  # type="GeoRedundant" 2x more expensive than LocallyRedundant
  # ZoneRedundant best for high availability but not supported in all regions


#  az dataprotection backup-vault update `
#    --resource-group $backupVaultRG `
#    --vault-name $vaultName `
#    --set identity.type=SystemAssigned

# Create the Storage Account (Standard_LRS is typically sufficient and cost-effective)
$storageAccountName="mystorageaccount20251104"

az storage account create `
  --name $storageAccountName `
  --resource-group $backupVaultRG `
  --location $Location `
  --sku Standard_LRS `
  --kind StorageV2

# Create the Blob Container
az storage container create `
  --name $blobContainerName `
  --account-name $storageAccountName `
  --auth-mode login


# Get the Backup Vault ID
$vaultId = az dataprotection backup-vault show `
  --resource-group $backupVaultRG `
  --vault-name $vaultName `
  --query id -o tsv

# Get the AKS Cluster Resource ID
$aksId = az aks show `
  --resource-group $RESOURCE_GROUP `
  --name $CLUSTER_NAME `
  --query id -o tsv

# Get the Principal ID of the Backup Vault&#8217;s Managed Identity

$vaultPrincipalId = az dataprotection backup-vault show `
--resource-group $backupVaultRG `
--vault-name $vaultName `
--query identity.principalId -o tsv

# Get the Snapshot Resource Group ID
$snapshotRgId = az group show `
  --name $SNAPSHOT_RG_NAME `
  --query id -o tsv

# Install the Backup Extension on AKS

az k8s-extension create `
    --name azure-aks-backup `
    --extension-type microsoft.dataprotection.kubernetes `
    --scope cluster `
    --cluster-type managedClusters `
    --cluster-name $CLUSTER_NAME `
    --resource-group $RESOURCE_GROUP `
    --configuration-settings blobContainer=$blobContainerName storageAccount=$storageAccountName storageAccountResourceGroup=$backupVaultRG storageAccountSubscriptionId=$(az account show --query id -o tsv)



# Get the Principal ID of the Backup Extension&#8217;s identity
$EXTENSION_IDENTITY_ID=$(az k8s-extension show `
    --name azure-aks-backup `
    --cluster-name $CLUSTER_NAME `
    --resource-group $RESOURCE_GROUP `
    --cluster-type managedClusters `
    --query aksAssignedIdentity.principalId `
    --output tsv)



# Get the Storage Account Resource ID
$STORAGE_ID=$(az storage account show `
    --name $storageAccountName `
    --resource-group $backupVaultRG `
    --query id `
    --output tsv)

# Get the Principal ID (Object ID) of your Backup Vault&#8217;s Managed Identity
#    (You should have this from previous steps: $vaultPrincipalId)

$VaultPrincipalId = (az backup vault show --name &#8220;MyAKSBackupVault&#8221; --resource-group &#8220;backup-vault&#8221; --query identity.principalId --output tsv)

# Assign the &#8216;Storage Blob Data Contributor&#8217; role
az role assignment create `
    --assignee-object-id $EXTENSION_IDENTITY_ID `
    --role 'Storage Blob Data Contributor' `
    --scope $STORAGE_ID

# The Backup Vault needs Trusted Access to the AKS cluster to interact with the extension.

az aks trustedaccess rolebinding create `
    --resource-group $RESOURCE_GROUP `
    --cluster-name $CLUSTER_NAME `
    --name "backup-vault-binding" `
    --source-resource-id $vaultId `
    --roles "Microsoft.DataProtection/backupVaults/backup-operator"


# Grant the Azure Backup Vault&#8217;s Managed Identity the Reader role permissions on the AKS cluster resource.

az role assignment create `
    --assignee-object-id $vaultPrincipalId `
    --role "Reader" `
    --scope $aksId `
    --assignee-principal-type "ServicePrincipal" `
    --name "18f7d05d-daf0-44f3-8aef-7df0b1b4b98c"



# Assign the &#8216;Data Operator for Managed Disks&#8217; role to the Vault&#8217;s MSI on the Snapshot Resource Group
az role assignment create `
    --assignee-object-id $VaultPrincipalId `
    --role "Data Operator for Managed Disks" `
    --scope $snapshotRgId `
    --assignee-principal-type "ServicePrincipal"


</code></pre><h2>Hooks in AKS backup</h2><p>In the context of <strong>Azure Backup for Azure Kubernetes Service (AKS)</strong>, <strong>hooks</strong> are a mechanism to ensure <strong>application-consistent backups</strong> of data stored in Persistent Volumes (PVs), particularly for stateful applications like databases.</p><p>Hooks are commands executed within a container <em>before</em> and <em>after</em> the Persistent Volume snapshots are taken. They are deployed as a <strong>Kubernetes Custom Resource (CR)</strong> called <code>BackupHook</code>.</p><p>The primary goal is to momentarily quiesce (stop writing to) the database, ensuring the snapshot captures a clean, consistent state that can be successfully restored.</p><h3>How It Works (Example: MySQL/PostgreSQL)</h3><ol><li><p><strong>Deployment:</strong> You define the hook logic in a <code>BackupHook</code> Custom Resource (CRD) and apply it to the AKS cluster using <code>kubectl apply -f &lt;hook-file&gt;.yaml</code>.</p></li><li><p><strong>Backup Job Starts:</strong> Azure Backup initiates a job.</p></li><li><p><strong>PreHook Execution:</strong> The Backup Extension executes the <code>preHooks</code> command inside the designated application container. The goal of application-consistent backup is to ensure the database&#8217;s data files are static while the volume snapshot is being taken. In MySQL, the command to achieve this is <code>FLUSH TABLES WITH READ LOCK;</code></p></li><li><p><strong>Snapshot:</strong> The CSI driver takes an incremental snapshot of the Azure Disk Persistent Volume.</p></li><li><p><strong>PostHook Execution:</strong> The Backup Extension executes the <code>postHooks</code> command inside the container (e.g., executing <code>UNLOCK TABLES;</code>).</p></li><li><p><strong>Backup Completes:</strong> The cluster state is copied to the blob container, and the backup job finishes.</p></li></ol><p>Apply below yaml before starting backup, modify namespaces which need to be backed up  and container name (to match ones in your deployments/statefull sets).</p><pre><code>apiVersion: clusterbackup.dataprotection.microsoft.com/v1alpha1
kind: BackupHook
metadata:
  name: bkphook-mysql
  namespace: default
spec:
  backupHook:
    - name: mysql-quiesce-hook
      includedNamespaces: 
      - default # The namespace where your MySQL StatefulSet is running
      
      preHooks:
        - exec:
            container: mysql
            command:
            - /usr/bin/mysql
            - -u
            - root
            - -pmypassword # Replace &#8216;mypassword&#8217; with your actual root password
            - -e
            - FLUSH TABLES WITH READ LOCK;
          
      
      postHooks:
        - exec:
            container: mysql
            command:
            - /usr/bin/mysql
            - -u
            - root
            - -pmypassword # Replace &#8216;mypassword&#8217; with your actual root password
            - -e
            - UNLOCK TABLES;
            </code></pre><p>Check if BackupHooks are running:</p><pre><code>kubectl get pods -n dataprotection-microsoft

NAME                                                         READY   STATUS    RESTARTS   AGE

dataprotection-microsoft-controller-5bc5d797f6-g4nr9         2/2     Running   0          3h30m

dataprotection-microsoft-geneva-service-5cccf95bc9-jxftn     2/2     Running   0          3h30m

dataprotection-microsoft-kubernetes-agent-8549cf9bf4-qh4qr   2/2     Running   0          3h30m

# Check BackupHooks logs
kubectl logs dataprotection-microsoft-controller-5bc5d797f6-g4nr9 | Select-String -Pattern "fsfreeze|hook"
</code></pre><p>In AKS resource,click on Backup blade</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!S2DL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515e91e-4641-4b9f-9932-5c6b6d92376e_1046x872.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!S2DL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515e91e-4641-4b9f-9932-5c6b6d92376e_1046x872.png 424w, https://substackcdn.com/image/fetch/$s_!S2DL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515e91e-4641-4b9f-9932-5c6b6d92376e_1046x872.png 848w, https://substackcdn.com/image/fetch/$s_!S2DL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515e91e-4641-4b9f-9932-5c6b6d92376e_1046x872.png 1272w, https://substackcdn.com/image/fetch/$s_!S2DL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515e91e-4641-4b9f-9932-5c6b6d92376e_1046x872.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!S2DL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515e91e-4641-4b9f-9932-5c6b6d92376e_1046x872.png" width="1046" height="872" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5515e91e-4641-4b9f-9932-5c6b6d92376e_1046x872.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:872,&quot;width&quot;:1046,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:84582,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/177977073?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515e91e-4641-4b9f-9932-5c6b6d92376e_1046x872.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!S2DL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515e91e-4641-4b9f-9932-5c6b6d92376e_1046x872.png 424w, https://substackcdn.com/image/fetch/$s_!S2DL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515e91e-4641-4b9f-9932-5c6b6d92376e_1046x872.png 848w, https://substackcdn.com/image/fetch/$s_!S2DL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515e91e-4641-4b9f-9932-5c6b6d92376e_1046x872.png 1272w, https://substackcdn.com/image/fetch/$s_!S2DL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5515e91e-4641-4b9f-9932-5c6b6d92376e_1046x872.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Select Azure backup vault and AKS cluster and click Next</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pOFo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86ff46a0-3adc-47bf-a291-10038c056d28_1093x970.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pOFo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86ff46a0-3adc-47bf-a291-10038c056d28_1093x970.png 424w, https://substackcdn.com/image/fetch/$s_!pOFo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86ff46a0-3adc-47bf-a291-10038c056d28_1093x970.png 848w, https://substackcdn.com/image/fetch/$s_!pOFo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86ff46a0-3adc-47bf-a291-10038c056d28_1093x970.png 1272w, https://substackcdn.com/image/fetch/$s_!pOFo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86ff46a0-3adc-47bf-a291-10038c056d28_1093x970.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pOFo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86ff46a0-3adc-47bf-a291-10038c056d28_1093x970.png" width="1093" height="970" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/86ff46a0-3adc-47bf-a291-10038c056d28_1093x970.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:970,&quot;width&quot;:1093,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:72620,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/177977073?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86ff46a0-3adc-47bf-a291-10038c056d28_1093x970.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pOFo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86ff46a0-3adc-47bf-a291-10038c056d28_1093x970.png 424w, https://substackcdn.com/image/fetch/$s_!pOFo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86ff46a0-3adc-47bf-a291-10038c056d28_1093x970.png 848w, https://substackcdn.com/image/fetch/$s_!pOFo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86ff46a0-3adc-47bf-a291-10038c056d28_1093x970.png 1272w, https://substackcdn.com/image/fetch/$s_!pOFo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86ff46a0-3adc-47bf-a291-10038c056d28_1093x970.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Configure backup frequency and click Next, in Datasources click add</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Q9mB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3eae49c-b3f4-4d5e-877b-5370b3504694_1285x1015.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Q9mB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3eae49c-b3f4-4d5e-877b-5370b3504694_1285x1015.png 424w, https://substackcdn.com/image/fetch/$s_!Q9mB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3eae49c-b3f4-4d5e-877b-5370b3504694_1285x1015.png 848w, https://substackcdn.com/image/fetch/$s_!Q9mB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3eae49c-b3f4-4d5e-877b-5370b3504694_1285x1015.png 1272w, https://substackcdn.com/image/fetch/$s_!Q9mB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3eae49c-b3f4-4d5e-877b-5370b3504694_1285x1015.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Q9mB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3eae49c-b3f4-4d5e-877b-5370b3504694_1285x1015.png" width="1285" height="1015" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e3eae49c-b3f4-4d5e-877b-5370b3504694_1285x1015.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1015,&quot;width&quot;:1285,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:63926,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/177977073?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3eae49c-b3f4-4d5e-877b-5370b3504694_1285x1015.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Q9mB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3eae49c-b3f4-4d5e-877b-5370b3504694_1285x1015.png 424w, https://substackcdn.com/image/fetch/$s_!Q9mB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3eae49c-b3f4-4d5e-877b-5370b3504694_1285x1015.png 848w, https://substackcdn.com/image/fetch/$s_!Q9mB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3eae49c-b3f4-4d5e-877b-5370b3504694_1285x1015.png 1272w, https://substackcdn.com/image/fetch/$s_!Q9mB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3eae49c-b3f4-4d5e-877b-5370b3504694_1285x1015.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Select what namespaces to include in backup </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!89BL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ef3fde4-c11c-4596-9b20-77265897068f_1300x580.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!89BL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ef3fde4-c11c-4596-9b20-77265897068f_1300x580.png 424w, https://substackcdn.com/image/fetch/$s_!89BL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ef3fde4-c11c-4596-9b20-77265897068f_1300x580.png 848w, https://substackcdn.com/image/fetch/$s_!89BL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ef3fde4-c11c-4596-9b20-77265897068f_1300x580.png 1272w, https://substackcdn.com/image/fetch/$s_!89BL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ef3fde4-c11c-4596-9b20-77265897068f_1300x580.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!89BL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ef3fde4-c11c-4596-9b20-77265897068f_1300x580.png" width="1300" height="580" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7ef3fde4-c11c-4596-9b20-77265897068f_1300x580.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:580,&quot;width&quot;:1300,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:43298,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/177977073?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ef3fde4-c11c-4596-9b20-77265897068f_1300x580.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!89BL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ef3fde4-c11c-4596-9b20-77265897068f_1300x580.png 424w, https://substackcdn.com/image/fetch/$s_!89BL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ef3fde4-c11c-4596-9b20-77265897068f_1300x580.png 848w, https://substackcdn.com/image/fetch/$s_!89BL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ef3fde4-c11c-4596-9b20-77265897068f_1300x580.png 1272w, https://substackcdn.com/image/fetch/$s_!89BL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ef3fde4-c11c-4596-9b20-77265897068f_1300x580.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In Backup Hooks, specify namespace and Hook CR</p><p><strong>Namespace</strong>: In hook YAML,  <code>namespace: default</code> under <code>metadata</code></p><p>apiVersion: clusterbackup.dataprotection.microsoft.com/v1alpha1</p><pre><code>kind: BackupHook

metadata:

name: bkphook-mysql

namespace: default</code></pre><p><strong>Hook CR Deployed:</strong> This is the name of the specific <code>BackupHook</code> Custom Resource </p><ul><li><p><strong>Value to enter:</strong> <code>bkphook-mysql</code></p></li><li><p><strong>Reason:</strong> In hook YAML, set <code>name: bkphook-mysql</code> under <code>metadata</code>.</p><p></p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!qGfx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70cf4ee1-0682-49cc-ae9a-89f9384fd1e7_1297x243.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qGfx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70cf4ee1-0682-49cc-ae9a-89f9384fd1e7_1297x243.png 424w, https://substackcdn.com/image/fetch/$s_!qGfx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70cf4ee1-0682-49cc-ae9a-89f9384fd1e7_1297x243.png 848w, https://substackcdn.com/image/fetch/$s_!qGfx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70cf4ee1-0682-49cc-ae9a-89f9384fd1e7_1297x243.png 1272w, https://substackcdn.com/image/fetch/$s_!qGfx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70cf4ee1-0682-49cc-ae9a-89f9384fd1e7_1297x243.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qGfx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70cf4ee1-0682-49cc-ae9a-89f9384fd1e7_1297x243.png" width="1297" height="243" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/70cf4ee1-0682-49cc-ae9a-89f9384fd1e7_1297x243.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:243,&quot;width&quot;:1297,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:18691,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/177977073?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70cf4ee1-0682-49cc-ae9a-89f9384fd1e7_1297x243.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!qGfx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70cf4ee1-0682-49cc-ae9a-89f9384fd1e7_1297x243.png 424w, https://substackcdn.com/image/fetch/$s_!qGfx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70cf4ee1-0682-49cc-ae9a-89f9384fd1e7_1297x243.png 848w, https://substackcdn.com/image/fetch/$s_!qGfx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70cf4ee1-0682-49cc-ae9a-89f9384fd1e7_1297x243.png 1272w, https://substackcdn.com/image/fetch/$s_!qGfx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F70cf4ee1-0682-49cc-ae9a-89f9384fd1e7_1297x243.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Select resource group for snapshot and click validate, if some permission are missing,just click on Assign missing roles and click configure backup</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8xjI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb40395-efb3-4a4d-808e-f72250198fbb_1847x972.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8xjI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb40395-efb3-4a4d-808e-f72250198fbb_1847x972.png 424w, https://substackcdn.com/image/fetch/$s_!8xjI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb40395-efb3-4a4d-808e-f72250198fbb_1847x972.png 848w, https://substackcdn.com/image/fetch/$s_!8xjI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb40395-efb3-4a4d-808e-f72250198fbb_1847x972.png 1272w, https://substackcdn.com/image/fetch/$s_!8xjI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb40395-efb3-4a4d-808e-f72250198fbb_1847x972.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8xjI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb40395-efb3-4a4d-808e-f72250198fbb_1847x972.png" width="1456" height="766" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/edb40395-efb3-4a4d-808e-f72250198fbb_1847x972.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:766,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:80250,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/177977073?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb40395-efb3-4a4d-808e-f72250198fbb_1847x972.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8xjI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb40395-efb3-4a4d-808e-f72250198fbb_1847x972.png 424w, https://substackcdn.com/image/fetch/$s_!8xjI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb40395-efb3-4a4d-808e-f72250198fbb_1847x972.png 848w, https://substackcdn.com/image/fetch/$s_!8xjI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb40395-efb3-4a4d-808e-f72250198fbb_1847x972.png 1272w, https://substackcdn.com/image/fetch/$s_!8xjI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedb40395-efb3-4a4d-808e-f72250198fbb_1847x972.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Click on three dots in Protection status and then click Backup Now</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fAGT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d58ea70-b87e-45a8-ba3d-a14d0c7c9526_1893x813.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fAGT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d58ea70-b87e-45a8-ba3d-a14d0c7c9526_1893x813.png 424w, https://substackcdn.com/image/fetch/$s_!fAGT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d58ea70-b87e-45a8-ba3d-a14d0c7c9526_1893x813.png 848w, https://substackcdn.com/image/fetch/$s_!fAGT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d58ea70-b87e-45a8-ba3d-a14d0c7c9526_1893x813.png 1272w, https://substackcdn.com/image/fetch/$s_!fAGT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d58ea70-b87e-45a8-ba3d-a14d0c7c9526_1893x813.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fAGT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d58ea70-b87e-45a8-ba3d-a14d0c7c9526_1893x813.png" width="1456" height="625" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8d58ea70-b87e-45a8-ba3d-a14d0c7c9526_1893x813.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:625,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:107785,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/177977073?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d58ea70-b87e-45a8-ba3d-a14d0c7c9526_1893x813.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!fAGT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d58ea70-b87e-45a8-ba3d-a14d0c7c9526_1893x813.png 424w, https://substackcdn.com/image/fetch/$s_!fAGT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d58ea70-b87e-45a8-ba3d-a14d0c7c9526_1893x813.png 848w, https://substackcdn.com/image/fetch/$s_!fAGT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d58ea70-b87e-45a8-ba3d-a14d0c7c9526_1893x813.png 1272w, https://substackcdn.com/image/fetch/$s_!fAGT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d58ea70-b87e-45a8-ba3d-a14d0c7c9526_1893x813.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CSvi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2926012d-2545-45f1-9c4d-f5a9b0b6eeb5_1469x1043.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CSvi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2926012d-2545-45f1-9c4d-f5a9b0b6eeb5_1469x1043.png 424w, https://substackcdn.com/image/fetch/$s_!CSvi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2926012d-2545-45f1-9c4d-f5a9b0b6eeb5_1469x1043.png 848w, https://substackcdn.com/image/fetch/$s_!CSvi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2926012d-2545-45f1-9c4d-f5a9b0b6eeb5_1469x1043.png 1272w, https://substackcdn.com/image/fetch/$s_!CSvi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2926012d-2545-45f1-9c4d-f5a9b0b6eeb5_1469x1043.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CSvi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2926012d-2545-45f1-9c4d-f5a9b0b6eeb5_1469x1043.png" width="1456" height="1034" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2926012d-2545-45f1-9c4d-f5a9b0b6eeb5_1469x1043.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1034,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:42857,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/177977073?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2926012d-2545-45f1-9c4d-f5a9b0b6eeb5_1469x1043.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!CSvi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2926012d-2545-45f1-9c4d-f5a9b0b6eeb5_1469x1043.png 424w, https://substackcdn.com/image/fetch/$s_!CSvi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2926012d-2545-45f1-9c4d-f5a9b0b6eeb5_1469x1043.png 848w, https://substackcdn.com/image/fetch/$s_!CSvi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2926012d-2545-45f1-9c4d-f5a9b0b6eeb5_1469x1043.png 1272w, https://substackcdn.com/image/fetch/$s_!CSvi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2926012d-2545-45f1-9c4d-f5a9b0b6eeb5_1469x1043.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Check backup status</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wDt8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb46aeed-eed5-4b66-b107-16ecee65f94d_1651x888.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wDt8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb46aeed-eed5-4b66-b107-16ecee65f94d_1651x888.png 424w, https://substackcdn.com/image/fetch/$s_!wDt8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb46aeed-eed5-4b66-b107-16ecee65f94d_1651x888.png 848w, https://substackcdn.com/image/fetch/$s_!wDt8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb46aeed-eed5-4b66-b107-16ecee65f94d_1651x888.png 1272w, https://substackcdn.com/image/fetch/$s_!wDt8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb46aeed-eed5-4b66-b107-16ecee65f94d_1651x888.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wDt8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb46aeed-eed5-4b66-b107-16ecee65f94d_1651x888.png" width="1456" height="783" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bb46aeed-eed5-4b66-b107-16ecee65f94d_1651x888.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:783,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:54964,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/177977073?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb46aeed-eed5-4b66-b107-16ecee65f94d_1651x888.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!wDt8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb46aeed-eed5-4b66-b107-16ecee65f94d_1651x888.png 424w, https://substackcdn.com/image/fetch/$s_!wDt8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb46aeed-eed5-4b66-b107-16ecee65f94d_1651x888.png 848w, https://substackcdn.com/image/fetch/$s_!wDt8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb46aeed-eed5-4b66-b107-16ecee65f94d_1651x888.png 1272w, https://substackcdn.com/image/fetch/$s_!wDt8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbb46aeed-eed5-4b66-b107-16ecee65f94d_1651x888.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Restoring from Backup</h2><p>On backup blade of AKS resource,click again on 3 dots on protection status-Restore </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pZJK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb642a5a-1160-414e-a810-e32262f0238f_1906x725.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pZJK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb642a5a-1160-414e-a810-e32262f0238f_1906x725.png 424w, https://substackcdn.com/image/fetch/$s_!pZJK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb642a5a-1160-414e-a810-e32262f0238f_1906x725.png 848w, https://substackcdn.com/image/fetch/$s_!pZJK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb642a5a-1160-414e-a810-e32262f0238f_1906x725.png 1272w, https://substackcdn.com/image/fetch/$s_!pZJK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb642a5a-1160-414e-a810-e32262f0238f_1906x725.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pZJK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb642a5a-1160-414e-a810-e32262f0238f_1906x725.png" width="1456" height="554" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fb642a5a-1160-414e-a810-e32262f0238f_1906x725.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:554,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:100646,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/177977073?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb642a5a-1160-414e-a810-e32262f0238f_1906x725.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pZJK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb642a5a-1160-414e-a810-e32262f0238f_1906x725.png 424w, https://substackcdn.com/image/fetch/$s_!pZJK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb642a5a-1160-414e-a810-e32262f0238f_1906x725.png 848w, https://substackcdn.com/image/fetch/$s_!pZJK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb642a5a-1160-414e-a810-e32262f0238f_1906x725.png 1272w, https://substackcdn.com/image/fetch/$s_!pZJK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffb642a5a-1160-414e-a810-e32262f0238f_1906x725.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Select restore point</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!k6lA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37bd6198-c7ec-4f3b-81ad-fc32b20f8ee1_1421x600.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!k6lA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37bd6198-c7ec-4f3b-81ad-fc32b20f8ee1_1421x600.png 424w, https://substackcdn.com/image/fetch/$s_!k6lA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37bd6198-c7ec-4f3b-81ad-fc32b20f8ee1_1421x600.png 848w, https://substackcdn.com/image/fetch/$s_!k6lA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37bd6198-c7ec-4f3b-81ad-fc32b20f8ee1_1421x600.png 1272w, https://substackcdn.com/image/fetch/$s_!k6lA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37bd6198-c7ec-4f3b-81ad-fc32b20f8ee1_1421x600.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!k6lA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37bd6198-c7ec-4f3b-81ad-fc32b20f8ee1_1421x600.png" width="1421" height="600" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/37bd6198-c7ec-4f3b-81ad-fc32b20f8ee1_1421x600.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:1421,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:37050,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/177977073?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37bd6198-c7ec-4f3b-81ad-fc32b20f8ee1_1421x600.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!k6lA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37bd6198-c7ec-4f3b-81ad-fc32b20f8ee1_1421x600.png 424w, https://substackcdn.com/image/fetch/$s_!k6lA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37bd6198-c7ec-4f3b-81ad-fc32b20f8ee1_1421x600.png 848w, https://substackcdn.com/image/fetch/$s_!k6lA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37bd6198-c7ec-4f3b-81ad-fc32b20f8ee1_1421x600.png 1272w, https://substackcdn.com/image/fetch/$s_!k6lA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F37bd6198-c7ec-4f3b-81ad-fc32b20f8ee1_1421x600.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uRjW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe20a40eb-09bf-4ffb-93d0-35f2251e92cc_941x1032.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uRjW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe20a40eb-09bf-4ffb-93d0-35f2251e92cc_941x1032.png 424w, https://substackcdn.com/image/fetch/$s_!uRjW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe20a40eb-09bf-4ffb-93d0-35f2251e92cc_941x1032.png 848w, https://substackcdn.com/image/fetch/$s_!uRjW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe20a40eb-09bf-4ffb-93d0-35f2251e92cc_941x1032.png 1272w, https://substackcdn.com/image/fetch/$s_!uRjW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe20a40eb-09bf-4ffb-93d0-35f2251e92cc_941x1032.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uRjW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe20a40eb-09bf-4ffb-93d0-35f2251e92cc_941x1032.png" width="941" height="1032" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e20a40eb-09bf-4ffb-93d0-35f2251e92cc_941x1032.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1032,&quot;width&quot;:941,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:67280,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/177977073?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe20a40eb-09bf-4ffb-93d0-35f2251e92cc_941x1032.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!uRjW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe20a40eb-09bf-4ffb-93d0-35f2251e92cc_941x1032.png 424w, https://substackcdn.com/image/fetch/$s_!uRjW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe20a40eb-09bf-4ffb-93d0-35f2251e92cc_941x1032.png 848w, https://substackcdn.com/image/fetch/$s_!uRjW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe20a40eb-09bf-4ffb-93d0-35f2251e92cc_941x1032.png 1272w, https://substackcdn.com/image/fetch/$s_!uRjW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe20a40eb-09bf-4ffb-93d0-35f2251e92cc_941x1032.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uWZx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7725f13e-d801-4f25-8b78-3ccbe5683068_1806x924.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uWZx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7725f13e-d801-4f25-8b78-3ccbe5683068_1806x924.png 424w, https://substackcdn.com/image/fetch/$s_!uWZx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7725f13e-d801-4f25-8b78-3ccbe5683068_1806x924.png 848w, https://substackcdn.com/image/fetch/$s_!uWZx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7725f13e-d801-4f25-8b78-3ccbe5683068_1806x924.png 1272w, https://substackcdn.com/image/fetch/$s_!uWZx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7725f13e-d801-4f25-8b78-3ccbe5683068_1806x924.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uWZx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7725f13e-d801-4f25-8b78-3ccbe5683068_1806x924.png" width="1456" height="745" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7725f13e-d801-4f25-8b78-3ccbe5683068_1806x924.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:745,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:89629,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/177977073?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7725f13e-d801-4f25-8b78-3ccbe5683068_1806x924.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!uWZx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7725f13e-d801-4f25-8b78-3ccbe5683068_1806x924.png 424w, https://substackcdn.com/image/fetch/$s_!uWZx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7725f13e-d801-4f25-8b78-3ccbe5683068_1806x924.png 848w, https://substackcdn.com/image/fetch/$s_!uWZx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7725f13e-d801-4f25-8b78-3ccbe5683068_1806x924.png 1272w, https://substackcdn.com/image/fetch/$s_!uWZx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7725f13e-d801-4f25-8b78-3ccbe5683068_1806x924.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/backup-and-restore-azure-kubernetes?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/backup-and-restore-azure-kubernetes?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/backup-and-restore-azure-kubernetes/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/backup-and-restore-azure-kubernetes/comments"><span>Leave a comment</span></a></p><p></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Connecting Kubernetes to Azure File Shares for Persistent, Shared Data on Azure Kubernetes Service - AKS]]></title><description><![CDATA[Azure file shares offer persistent data that can be accessed by multiple pods simultaneously.Unlike Azure Disks, which are typically restricted to a single pod, Azure File Shares provide ReadWriteMany access, making them perfect for scenarios like shared configuration files, content management systems, or multi-instance applications needing a common data store.]]></description><link>https://adminjournal.substack.com/p/connecting-kubernetes-to-azure-file</link><guid isPermaLink="false">https://adminjournal.substack.com/p/connecting-kubernetes-to-azure-file</guid><dc:creator><![CDATA[Драган Вучановић]]></dc:creator><pubDate>Mon, 03 Nov 2025 13:02:59 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!R9GZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41a633b2-e6d4-4e22-b68c-b2d63e922176_564x508.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!R9GZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41a633b2-e6d4-4e22-b68c-b2d63e922176_564x508.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!R9GZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41a633b2-e6d4-4e22-b68c-b2d63e922176_564x508.png 424w, https://substackcdn.com/image/fetch/$s_!R9GZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41a633b2-e6d4-4e22-b68c-b2d63e922176_564x508.png 848w, https://substackcdn.com/image/fetch/$s_!R9GZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41a633b2-e6d4-4e22-b68c-b2d63e922176_564x508.png 1272w, https://substackcdn.com/image/fetch/$s_!R9GZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41a633b2-e6d4-4e22-b68c-b2d63e922176_564x508.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!R9GZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41a633b2-e6d4-4e22-b68c-b2d63e922176_564x508.png" width="564" height="508" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/41a633b2-e6d4-4e22-b68c-b2d63e922176_564x508.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:508,&quot;width&quot;:564,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:331914,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/177881237?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41a633b2-e6d4-4e22-b68c-b2d63e922176_564x508.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!R9GZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41a633b2-e6d4-4e22-b68c-b2d63e922176_564x508.png 424w, https://substackcdn.com/image/fetch/$s_!R9GZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41a633b2-e6d4-4e22-b68c-b2d63e922176_564x508.png 848w, https://substackcdn.com/image/fetch/$s_!R9GZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41a633b2-e6d4-4e22-b68c-b2d63e922176_564x508.png 1272w, https://substackcdn.com/image/fetch/$s_!R9GZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F41a633b2-e6d4-4e22-b68c-b2d63e922176_564x508.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Azure file shares offer persistent data that can be accessed by <strong>multiple pods simultaneously.</strong>Unlike Azure Disks, which are typically restricted to a single pod, Azure File Shares provide <strong>ReadWriteMany</strong> access, making them perfect for scenarios like shared configuration files, content management systems, or multi-instance applications needing a common data store.</p><p>Storage account mysa202510 in aks resource group with share name myshare was used.<code>azure-secret</code> is necessary for Persistent Volume (PV):</p><p>The <strong>Persistent Volume (PV)</strong> definition is merely metadata in Kubernetes. To actually connect to and mount the remote Azure File Share, the underlying mechanism&#8212;the Azure File CSI Driver running on the node&#8212;must present valid credentials to the Azure Storage service.</p><ol><li><p><strong>Azure File Uses SMB/CIFS:</strong> Azure File Shares are accessed using the SMB (Server Message Block) protocol (also known as CIFS). This protocol requires a <strong>username</strong> and a <strong>password</strong> to establish a secure connection, even if the storage account is publicly accessible.</p></li><li><p><strong>Required Credentials:</strong> The credentials used are the <strong>Azure Storage Account Name</strong> (which acts as the username) and the <strong>Storage Account Key</strong> (which acts as the password).</p></li><li><p><strong>Kubernetes Secret&#8217;s Role:</strong> The Kubernetes Secret resource (<code>azure-secret</code> in this case) is the secure, native way to store these sensitive credentials. It holds the Storage Account Name under the key <code>azurestorageaccountname</code> and the Storage Account Key under <code>azurestorageaccountkey</code>.</p></li></ol><p>The <code>nodeStageSecretRef</code> section in PV acts as a pointer to these credentials:</p><ul><li><p><strong>PV Definition:</strong> The <code>nodeStageSecretRef</code> points to the <code>azure-secret</code> in the <code>default</code> namespace.</p></li><li><p><strong>Kubelet Action:</strong> When a Pod needs to mount the PV, the Kubelet on the worker node reads the PV definition.</p></li><li><p><strong>CSI Driver Access:</strong> The <strong>Azure File CSI Driver</strong> sees the secret reference, retrieves the credentials from the secret, and constructs the necessary <code>mount -t cifs</code> command:</p><p><code>mount -t cifs -o username=mysa202510,password=&lt;STORAGE_KEY&gt;,... //mysa202510.file.core.windows.net/myshare /mnt/azure </code></p></li></ul><p>Without the Secret, the CSI driver has no way to authenticate the mount requests.</p><pre><code><code>$AZURE_STORAGE_CONNECTION_STRING=$(az storage account show-connection-string --name mysa202510 --resource-group aks --query connectionString --output tsv)
# Create azure share
az storage share create --name myshare --connection-string $AZURE_STORAGE_CONNECTION_STRING
# Get storage key
$STORAGE_KEY=$(az storage account keys list --account-name mysa202510 --resource-group aks --query &#8220;[0].value&#8221; --output tsv)
# Create Kubernetes secret to tell AKS how to authenticate to storage account
kubectl create secret generic azure-secret `
  --from-literal=azurestorageaccountname=$AKS_PERS_STORAGE_ACCOUNT_NAME `
  --from-literal=azurestorageaccountkey=$STORAGE_KEY</code></code></pre><p>The PersistentVolume (PV) object is Kubernetes&#8217; way of knowing about existing Azure File Share. It&#8217;s a cluster-scoped resource that describes the actual cloud storage.</p><p>Create a file named <code>azurefile-pv.yaml and apply it.</code></p><pre><code>apiVersion: v1
kind: PersistentVolume
metadata:
  name: azurefile-pv
spec:
  capacity:
    storage: 5Gi  # Size of your Azure File Share
  accessModes:
    - ReadWriteMany  # Crucial: Allows multiple pods to read/write
  persistentVolumeReclaimPolicy: Retain  # Don&#8217;t delete the Azure File Share if PVC is deleted
  storageClassName: azurefile-sc  # Logical name to match with PVC
  csi:
    driver: file.csi.azure.com  # The Azure File CSI driver
    volumeHandle: "mysa202510/myshare"  # Format: &lt;StorageAccountName&gt;/&lt;FileShareName&gt;
    readOnly: false
    volumeAttributes:
      shareName: "myshare"
    nodeStageSecretRef:
      name: azure-secret  # Reference to our secret
      namespace: default  # Namespace where the secret lives
  mountOptions:
    - dir_mode=0777 # Directory permissions
    - file_mode=0777 # File permissions
    - uid=1000 # Map files to UID 1000 inside container
    - gid=1000 # Map files to GID 1000 inside container</code></pre><p>The PersistentVolumeClaim (PVC) is a request for storage from an application. In static provisioning, the PVC explicitly claims a specific PV.</p><p>Create a file named <code>azurefile-pvc.yaml</code> and apply it</p><pre><code>apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: azurefile
spec:
  accessModes:
    - ReadWriteMany  # Must match the PV&#8217;s access mode
  storageClassName: azurefile-sc  # Must match the PV&#8217;s StorageClass
  volumeName: azurefile-pv  # Explicitly binds to our 'azurefile-pv'
  resources:
    requests:
      storage: 5Gi  # Requested storage (must be &lt;= PV capacity)</code></pre><p>Finally, let&#8217;s deploy a simple Nginx pod that will mount Azure File Share.</p><p>Create a file named <code>nginx-pod.yaml and apply it</code></p><pre><code>apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: mypod
      image: mcr.microsoft.com/oss/nginx/nginx:1.21.6
      resources:
        limits:
          memory: "128Mi"
          cpu: "500m"
        requests:
          memory: "64Mi"
          cpu: "250m"
      volumeMounts:
        - name: azure-storage
          mountPath: "/mnt/azure"  # The path inside the container
  volumes:
    - name: azure-storage
      persistentVolumeClaim:
        claimName: azurefile  # Reference to our PVC</code></pre><p>Create example data inside pod</p><pre><code>kubectl exec -it mypod-nginx -- touch touch /mnt/azure/test_file_$(date +%s).txt
# verify data are present
kubectl exec -it mypod -- ls -l /mnt/azure/      
total 0
-rwxrwxrwx 1 1000 1000 0 Nov  3 12:22 test_file_1762172563.txt</code></pre><p>Data should be visible in Azure portal as well</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_HtV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e6fa8a6-1a9a-4281-825a-07e4ba923a0a_1896x477.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_HtV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e6fa8a6-1a9a-4281-825a-07e4ba923a0a_1896x477.png 424w, https://substackcdn.com/image/fetch/$s_!_HtV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e6fa8a6-1a9a-4281-825a-07e4ba923a0a_1896x477.png 848w, https://substackcdn.com/image/fetch/$s_!_HtV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e6fa8a6-1a9a-4281-825a-07e4ba923a0a_1896x477.png 1272w, https://substackcdn.com/image/fetch/$s_!_HtV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e6fa8a6-1a9a-4281-825a-07e4ba923a0a_1896x477.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_HtV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e6fa8a6-1a9a-4281-825a-07e4ba923a0a_1896x477.png" width="1456" height="366" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2e6fa8a6-1a9a-4281-825a-07e4ba923a0a_1896x477.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:366,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:64682,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/177881237?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e6fa8a6-1a9a-4281-825a-07e4ba923a0a_1896x477.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_HtV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e6fa8a6-1a9a-4281-825a-07e4ba923a0a_1896x477.png 424w, https://substackcdn.com/image/fetch/$s_!_HtV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e6fa8a6-1a9a-4281-825a-07e4ba923a0a_1896x477.png 848w, https://substackcdn.com/image/fetch/$s_!_HtV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e6fa8a6-1a9a-4281-825a-07e4ba923a0a_1896x477.png 1272w, https://substackcdn.com/image/fetch/$s_!_HtV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e6fa8a6-1a9a-4281-825a-07e4ba923a0a_1896x477.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/connecting-kubernetes-to-azure-file?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/connecting-kubernetes-to-azure-file?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/connecting-kubernetes-to-azure-file/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/connecting-kubernetes-to-azure-file/comments"><span>Leave a comment</span></a></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[How to Snapshot and Restore MySQL on Azure Kubernetes Service - AKS]]></title><description><![CDATA[An Azure AKS snapshot is a point-in-time, read-only copy of an Azure Managed Disk that is used as a Persistent Volume (PV) by a stateful application running in Azure Kubernetes Service (AKS) cluster.]]></description><link>https://adminjournal.substack.com/p/how-to-snapshot-and-restore-mysql</link><guid isPermaLink="false">https://adminjournal.substack.com/p/how-to-snapshot-and-restore-mysql</guid><dc:creator><![CDATA[Драган Вучановић]]></dc:creator><pubDate>Mon, 03 Nov 2025 10:43:57 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ikBk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c2abfab-c8ee-4cc4-ae87-49f896d41bff_551x565.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ikBk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c2abfab-c8ee-4cc4-ae87-49f896d41bff_551x565.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ikBk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c2abfab-c8ee-4cc4-ae87-49f896d41bff_551x565.png 424w, https://substackcdn.com/image/fetch/$s_!ikBk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c2abfab-c8ee-4cc4-ae87-49f896d41bff_551x565.png 848w, https://substackcdn.com/image/fetch/$s_!ikBk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c2abfab-c8ee-4cc4-ae87-49f896d41bff_551x565.png 1272w, https://substackcdn.com/image/fetch/$s_!ikBk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c2abfab-c8ee-4cc4-ae87-49f896d41bff_551x565.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ikBk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c2abfab-c8ee-4cc4-ae87-49f896d41bff_551x565.png" width="551" height="565" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0c2abfab-c8ee-4cc4-ae87-49f896d41bff_551x565.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:565,&quot;width&quot;:551,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:222790,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/177871212?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c2abfab-c8ee-4cc4-ae87-49f896d41bff_551x565.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ikBk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c2abfab-c8ee-4cc4-ae87-49f896d41bff_551x565.png 424w, https://substackcdn.com/image/fetch/$s_!ikBk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c2abfab-c8ee-4cc4-ae87-49f896d41bff_551x565.png 848w, https://substackcdn.com/image/fetch/$s_!ikBk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c2abfab-c8ee-4cc4-ae87-49f896d41bff_551x565.png 1272w, https://substackcdn.com/image/fetch/$s_!ikBk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c2abfab-c8ee-4cc4-ae87-49f896d41bff_551x565.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>An <strong>Azure AKS snapshot</strong> is a <strong>point-in-time, read-only copy of an Azure Managed Disk</strong> that is used as a <strong>Persistent Volume (PV)</strong> by a stateful application running in Azure Kubernetes Service (AKS) cluster.</p><p>This feature is implemented using the Kubernetes <strong>Container Storage Interface (CSI) Volume Snapshot</strong> API.</p><div><hr></div><h2>Key Characteristics</h2><ul><li><p><strong>Data Protection:</strong> Its primary role is for <strong>backup, recovery, and data protection</strong>. It captures the data on the persistent disk at an exact moment, allowing you to restore the volume to that previous state.</p></li><li><p><strong>Kubernetes-Native:</strong> It&#8217;s managed through standard Kubernetes resources: the <code>VolumeSnapshotClass</code> (which defines parameters like incremental backup and the Azure Disk driver) and the <code>VolumeSnapshot</code> object (which requests the snapshot of a specific Persistent Volume Claim, or PVC).</p></li><li><p><strong>Storage Source:</strong> The snapshot lives as an object within Azure subscription&#8217;s resource group. It can be used as the <strong>data source</strong> to create a <strong>new</strong> Persistent Volume (Azure Managed Disk).</p></li></ul><h2>Use Cases<strong> </strong></h2><ul><li><p><strong>Quickly roll back a volume to a clean state after accidental data corruption or deletion.</strong></p></li><li><p>Create a <strong>new, isolated environment</strong> (e.g., development or testing) with a copy of production data for debugging or validation.</p></li><li><p>The underlying Azure Disk snapshot can be used to copy data to a different region or migrate workloads between AKS clusters.</p></li><li><p>It is the technical foundation used by advanced backup solutions like <strong>Azure Backup for AKS</strong> and <strong>Velero</strong> to capture the data portion of an application backup.</p></li></ul><p>First, let&#8217;s deploy our MySQL database using a Kubernetes <code>StatefulSet</code>. This ensures our database gets stable identities and persistent storage (an Azure Managed Disk).</p><pre><code>apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
  namespace: default
spec:
  serviceName: "mysql-headless" # A dedicated Headless Service is required for StatefulSets
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.0
        ports:
        - containerPort: 3306
          name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: my-secret-password # Should use a Kubernetes Secret in production!
        volumeMounts:
        - name: mysql-data # Links to the volumeClaimTemplate below
          mountPath: /var/lib/mysql
  # --- 1. THE VOLUME CLAIM TEMPLATE ---
  volumeClaimTemplates:
  - metadata:
      name: mysql-data # The name referenced in volumeMounts above
    spec:
      accessModes:
        - ReadWriteOnce # Correct for a database (Azure Disk)
      storageClassName: managed-premium # Your chosen StorageClass
      resources:
        requests:
          storage: 5Gi # Your chosen storage size
---
# Dedicated Headless Service (Required by StatefulSet)
apiVersion: v1
kind: Service
metadata:
  name: mysql-headless
  namespace: default
  labels:
    app: mysql
spec:
  ports:
  - port: 3306
    name: mysql
  clusterIP: None # Makes this a Headless Service
  selector:
    app: mysql</code></pre><p>  Test pods:</p><pre><code>kubectl get pods
NAME      READY   STATUS    RESTARTS   AGE
mysql-0   1/1     Running   0          9m45s</code></pre><p>Create and copy SQL script into running pod</p><pre><code>kubectl exec -it mysql-0 -- bash -c "cat &lt;&lt;EOF &gt; /tmp/test-data.sql
&gt;&gt; CREATE DATABASE IF NOT EXISTS snapshot_test_db;
&gt;&gt; USE snapshot_test_db;
&gt;&gt; CREATE TABLE IF NOT EXISTS inventory (
&gt;&gt;     id INT AUTO_INCREMENT PRIMARY KEY,
&gt;&gt;     item_name VARCHAR(100) NOT NULL,
&gt;&gt;     quantity INT NOT NULL,
&gt;&gt;     data_creation_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
&gt;&gt; );
&gt;&gt; INSERT INTO inventory (item_name, quantity) VALUES ('Widget A', 100);
&gt;&gt; INSERT INTO inventory (item_name, quantity) VALUES ('Gadget B', 50);
&gt;&gt; EOF"</code></pre><p>Execute the script to create test database and table</p><pre><code>kubectl exec -it mysql-0 -- bash -c "mysql -u root -p'my-secret-password' &lt; /tmp/test-data.sql"</code></pre><p>Verify the data</p><pre><code>kubectl exec -it mysql-0 -- bash -c "mysql -u root -p'my-secret-password' &lt; /tmp/test-data.sql"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+-----------+----------+---------------------+
| id | item_name | quantity | data_creation_time  |
+----+-----------+----------+---------------------+
|  1 | Widget A  |      100 | 2025-11-03 09:21:34 |
|  2 | Gadget B  |       50 | 2025-11-03 09:21:34 |
+----+-----------+----------+---------------------+</code></pre><h2>Create the VolumeSnapshotClass</h2><p>The <code>VolumeSnapshotClass</code> defines the driver and parameters for how the snapshot should be created on Azure. Since you are using Azure Disks, you&#8217;ll specify the <code>disk.csi.azure.com</code> provisioner.</p><p>Create a file named <code>azuredisk-vsc.yaml</code> with the following content:</p><pre><code>apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
  name: csi-azuredisk-vsc
driver: disk.csi.azure.com # This is the Azure Disk CSI driver
deletionPolicy: Delete # Set to Delete to automatically remove the Azure snapshot when the K8s object is deleted, or Retain to keep it.
parameters:
  incremental: "true" # Creates incremental snapshots, which are faster and more storage-efficient.</code></pre><p>Apply and verify the class</p><pre><code>apply -f azuredisk-vsc.yaml
kubectl get volumesnapshotclass
NAME                DRIVER               DELETIONPOLICY   AGE
csi-azuredisk-vsc   disk.csi.azure.com   Delete           44m</code></pre><h2>Create the VolumeSnapshot</h2><p>Now create the <code>VolumeSnapshot</code> resource, which references the <code>VolumeSnapshotClass</code> just created and the specific <strong>Persistent Volume Claim (PVC)</strong> associated with MySQL StatefulSet.</p><p>The name of  PVC is <code>mysql-data-mysql-0</code> (based on StatefulSet configuration: <code>volumeClaimTemplates</code> name <code>mysql-data</code> + StatefulSet name <code>mysql</code> + ordinal <code>0</code>).</p><p>Create a file named <code>mysql-snapshot.yaml</code> with the following content:</p><pre><code>apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: mysql-data-initial-snapshot # Give snapshot a descriptive name
  namespace: default
spec:
  # Reference the VolumeSnapshotClass created in previous step.
  volumeSnapshotClassName: csi-azuredisk-vsc
  source:
    # Reference the specific PVC of your StatefulSet Pod
    persistentVolumeClaimName: mysql-data-mysql-0</code></pre><p>Apply and check snapshot</p><pre><code>kubectl apply -f mysql-snapshot.yaml
kubectl get volumesnapshot mysql-data-initial-snapshot     
NAME                          READYTOUSE   SOURCEPVC            SOURCESNAPSHOTCONTENT   RESTORESIZE   SNAPSHOTCLASS       SNAPSHOTCONTENT                                    CREATIONTIME   AGE
mysql-data-initial-snapshot   true         mysql-data-mysql-0                           5Gi           csi-azuredisk-vsc   snapcontent-ff1edf44-3104-4ae6-a5f4-7eda16f86c8f   48m           
 48m</code></pre><p><strong>Simulate data loss</strong></p><p>First, delete the test data to simulate the accident and verify data were lost</p><pre><code>kubectl exec -it mysql-0 -- mysql -u root -p"my-secret-password" -e "DROP DATABASE snapshot_test_db;"
kubectl exec -it mysql-0 -- mysql -u root -p"my-secret-password" -e "SELECT * FROM snapshot_test_db.inventory;"
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1049 (42000) at line 1: Unknown database 'snapshot_test_db'
command terminated with exit code 1</code></pre><p><strong>Restore from Snapshot</strong></p><p>Scale your MySQL StatefulSet to zero replicas. This cleanly shuts down the Pod and <strong>unmounts the corrupt Azure Disk</strong> from the node.</p><pre><code>kubectl scale statefulset mysql --replicas=0</code></pre><p>Delete original PVC</p><pre><code>kubectl delete pvc mysql-data-mysql-0</code></pre><p>Create a new Persistent Volume Claim (PVC) that uses the existing <code>VolumeSnapshot</code> as its data source and name matched original PVC we jusr deleted.Create a file named <code>mysql-restore-pvc.yaml</code></p><pre><code>apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-data-mysql-0 # Match the original PVC name
  namespace: default
spec:
  # The new PVC MUST match the original StorageClass and size
  storageClassName: managed-premium 
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi # MUST be equal to or greater than the original PVC size
  dataSource: # &lt;--- This block is the key to restoration!
    name: mysql-data-initial-snapshot # The name of your VolumeSnapshot object
    kind: VolumeSnapshot
    apiGroup: snapshot.storage.k8s.io</code></pre><pre><code>kubectl apply -f mysql-restore-pvc.yaml
kubectl describe pvc mysql-data-mysql-0
Name:          mysql-data-mysql-0
Namespace:     default
StorageClass:  managed-premium
Status:        Pending
Volume:
Labels:        &lt;none&gt;
Annotations:   &lt;none&gt;
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:
Access Modes:
VolumeMode:    Filesystem
DataSource:
  APIGroup:  snapshot.storage.k8s.io
  Kind:      VolumeSnapshot
  Name:      mysql-data-initial-snapshot
Used By:     &lt;none&gt;
Events:
  Type    Reason                Age               From                         Message
  ----    ------                ----              ----                         -------
  Normal  WaitForFirstConsumer  4s (x4 over 45s)  persistentvolume-controller  waiting for first consumer to be created before binding</code></pre><p><code>volumeBindingMode: WaitForFirstConsumer</code>.</p><p><strong>What this means:</strong> Kubernetes will <strong>not</strong> provision the actual Azure Disk (or the PV derived from the snapshot) until a <strong>Pod</strong> (the &#8220;consumer&#8221;) is scheduled and requests to use this PVC. This helps the scheduler choose the best node first, preventing the node affinity conflicts we discussed earlier.</p><p><strong>Current State:</strong> We have created the new PVC (<code>mysql-data-mysql-0</code>), but we have <strong>not yet scaled up the StatefulSet</strong>. Since no Pod is requesting this PVC yet, it remains in the <code>Pending</code> state.</p><p>Now that the PVC with the expected name (<code>mysql-data-mysql-0</code>) is present and sourced from the good snapshot data, we can scale the StatefulSet back up.</p><pre><code>kubectl scale statefulset mysql --replicas=1</code></pre><p>Testing that data were restored</p><pre><code>kubectl exec -it mysql-0 -- mysql -u root -p"my-secret-password" -e "SELECT * FROM snapshot_test_db.inventory;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----+-----------+----------+---------------------+
| id | item_name | quantity | data_creation_time  |
+----+-----------+----------+---------------------+
|  1 | Widget A  |      100 | 2025-11-03 09:21:34 |
|  2 | Gadget B  |       50 | 2025-11-03 09:21:34 |
+----+-----------+----------+---------------------+</code></pre><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading SysAdmin Journal! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/how-to-snapshot-and-restore-mysql/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/how-to-snapshot-and-restore-mysql/comments"><span>Leave a comment</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/how-to-snapshot-and-restore-mysql?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/how-to-snapshot-and-restore-mysql?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p>]]></content:encoded></item><item><title><![CDATA[Building a Robust CI/CD Pipeline for Go Apps on Kubernetes with Azure DevOps, Helm, Nginx, and Cert-Manager]]></title><description><![CDATA[Simple Web frontend Go application and backed MySQL server were aimed for a production-ready setup.]]></description><link>https://adminjournal.substack.com/p/building-a-robust-azure-devops-cicd</link><guid isPermaLink="false">https://adminjournal.substack.com/p/building-a-robust-azure-devops-cicd</guid><dc:creator><![CDATA[Драган Вучановић]]></dc:creator><pubDate>Fri, 24 Oct 2025 07:50:35 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!87N7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe66d48ba-5723-4d00-818f-baea51fc518b_863x452.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!87N7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe66d48ba-5723-4d00-818f-baea51fc518b_863x452.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!87N7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe66d48ba-5723-4d00-818f-baea51fc518b_863x452.png 424w, https://substackcdn.com/image/fetch/$s_!87N7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe66d48ba-5723-4d00-818f-baea51fc518b_863x452.png 848w, https://substackcdn.com/image/fetch/$s_!87N7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe66d48ba-5723-4d00-818f-baea51fc518b_863x452.png 1272w, https://substackcdn.com/image/fetch/$s_!87N7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe66d48ba-5723-4d00-818f-baea51fc518b_863x452.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!87N7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe66d48ba-5723-4d00-818f-baea51fc518b_863x452.png" width="863" height="452" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e66d48ba-5723-4d00-818f-baea51fc518b_863x452.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:452,&quot;width&quot;:863,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:228083,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/176990147?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe66d48ba-5723-4d00-818f-baea51fc518b_863x452.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!87N7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe66d48ba-5723-4d00-818f-baea51fc518b_863x452.png 424w, https://substackcdn.com/image/fetch/$s_!87N7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe66d48ba-5723-4d00-818f-baea51fc518b_863x452.png 848w, https://substackcdn.com/image/fetch/$s_!87N7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe66d48ba-5723-4d00-818f-baea51fc518b_863x452.png 1272w, https://substackcdn.com/image/fetch/$s_!87N7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe66d48ba-5723-4d00-818f-baea51fc518b_863x452.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Simple Web frontend Go application and backed MySQL server were aimed for a production-ready setup. Application is deployed to Azure Kubernetes cluster and Azure Docker registry.Along the way, this pipeline includes:</p><ul><li><p>Setting up Go-specific CI tasks (testing, linting, code coverage).</p></li><li><p>Building and scanning Docker images.</p></li><li><p>Automating deployments to Dev and Production namespaces using Helm.</p></li><li><p>Configuring Nginx Ingress for traffic routing.</p></li><li><p>Automating SSL/TLS certificates with Cert-Manager.</p></li></ul><p>Variables are stored in AzureDevOps portal</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!urbF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed919596-0bd1-430a-b67d-550f99833425_567x987.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!urbF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed919596-0bd1-430a-b67d-550f99833425_567x987.png 424w, https://substackcdn.com/image/fetch/$s_!urbF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed919596-0bd1-430a-b67d-550f99833425_567x987.png 848w, https://substackcdn.com/image/fetch/$s_!urbF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed919596-0bd1-430a-b67d-550f99833425_567x987.png 1272w, https://substackcdn.com/image/fetch/$s_!urbF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed919596-0bd1-430a-b67d-550f99833425_567x987.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!urbF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed919596-0bd1-430a-b67d-550f99833425_567x987.png" width="567" height="987" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ed919596-0bd1-430a-b67d-550f99833425_567x987.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:987,&quot;width&quot;:567,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:35745,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/176990147?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed919596-0bd1-430a-b67d-550f99833425_567x987.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!urbF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed919596-0bd1-430a-b67d-550f99833425_567x987.png 424w, https://substackcdn.com/image/fetch/$s_!urbF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed919596-0bd1-430a-b67d-550f99833425_567x987.png 848w, https://substackcdn.com/image/fetch/$s_!urbF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed919596-0bd1-430a-b67d-550f99833425_567x987.png 1272w, https://substackcdn.com/image/fetch/$s_!urbF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed919596-0bd1-430a-b67d-550f99833425_567x987.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Code location: <a href="https://github.com/dragan1979/azuredevops-go/tree/main">my github repository</a></p><h4>The CI Stage: Ensuring Code Quality and Container Security</h4><p>Our pipeline begins with a <code>Build</code> stage, focused on ensuring our Go application&#8217;s quality and container integrity.</p><p></p><ol><li><p><strong>Code Quality (SonarCloud):</strong></p><ul><li><p><code>SonarCloudPrepare@3</code>: Configures SonarCloud for static code analysis, integrating test results and coverage reports.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!f2ZS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c39f5c3-27a3-4d65-adc2-27470e25804c_1918x1003.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!f2ZS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c39f5c3-27a3-4d65-adc2-27470e25804c_1918x1003.png 424w, https://substackcdn.com/image/fetch/$s_!f2ZS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c39f5c3-27a3-4d65-adc2-27470e25804c_1918x1003.png 848w, https://substackcdn.com/image/fetch/$s_!f2ZS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c39f5c3-27a3-4d65-adc2-27470e25804c_1918x1003.png 1272w, https://substackcdn.com/image/fetch/$s_!f2ZS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c39f5c3-27a3-4d65-adc2-27470e25804c_1918x1003.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!f2ZS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c39f5c3-27a3-4d65-adc2-27470e25804c_1918x1003.png" width="1456" height="761" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5c39f5c3-27a3-4d65-adc2-27470e25804c_1918x1003.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:761,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:124769,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/176990147?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c39f5c3-27a3-4d65-adc2-27470e25804c_1918x1003.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!f2ZS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c39f5c3-27a3-4d65-adc2-27470e25804c_1918x1003.png 424w, https://substackcdn.com/image/fetch/$s_!f2ZS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c39f5c3-27a3-4d65-adc2-27470e25804c_1918x1003.png 848w, https://substackcdn.com/image/fetch/$s_!f2ZS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c39f5c3-27a3-4d65-adc2-27470e25804c_1918x1003.png 1272w, https://substackcdn.com/image/fetch/$s_!f2ZS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c39f5c3-27a3-4d65-adc2-27470e25804c_1918x1003.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><ul><li><p><code>Bash@3</code> (<code>go fmt</code>): Enforces consistent code formatting.</p></li><li><p><code>Bash@3</code> (<code>go mod tidy</code>): Manages Go modules, ensuring dependencies are clean and accurate.</p></li></ul></li></ol><p></p><ol><li><p><strong>Testing and Coverage:</strong></p><ul><li><p><code>Bash@3</code> (Go Tests): Runs unit tests, generates JUnit XML reports (for test results) and Cobertura XML reports (for code coverage) using <code>go-junit-report</code> and <code>gocover-cobertura</code>. It also generates an HTML coverage report.</p></li><li><p><code>PublishTestResults@2</code> &amp; <code>PublishCodeCoverageResults@2</code>: Integrates these reports directly into Azure DevOps for easy visualization.</p></li></ul></li><li><p><strong>Application Build (</strong><code>Go@0</code><strong>):</strong> Compiles the Go application.</p></li><li><p><strong>SonarCloud Analysis &amp; Publish:</strong> Runs the actual analysis and publishes results to SonarCloud.</p></li><li><p><strong>Docker Image Build &amp; Push (</strong><code>DockerCompose@1</code><strong>):</strong></p><ul><li><p>Builds the Docker image for the Go application.</p></li><li><p>Pushes the image to Azure Container Registry (ACR) with a unique <code>Build.BuildId</code> tag, and importantly, also with <code>latest</code> for easy local testing.</p></li></ul></li><li><p><strong>Container Security Scan (Trivy):</strong></p><ul><li><p>Downloads the Trivy JUnit template.</p></li><li><p>Logs into ACR.</p></li><li><p><code>Bash@3</code> (Trivy Scan): Scans the newly built Docker image for vulnerabilities (High and Critical severity) and generates a JUnit XML report. We even included logic to create a dummy report if the scan fails or finds no issues, ensuring the pipeline doesn&#8217;t break.</p></li><li><p><code>PublishTestResults@2</code>: Publishes Trivy results to Azure DevOps.</p></li></ul></li></ol><p>In this stage Build and publish artifacts tasks are actually not needed because building is done in next stage,but posted anyway for demonstrations</p><h4>The CD Stages: Deploying to Dev and Production</h4><p>After a successful build, the pipeline moves to the deployment stages. We maintain strict separation between Dev and Production environments.</p><p><strong>Prerequisites (Manual Setup - Run Once Per Cluster):</strong></p><p>Before these stages run, four critical components must be installed directly in Kubernetes cluster:</p><ol><li><p><strong>Nginx Ingress Controller:</strong> This acts as the external entry point (<code>LoadBalancer</code>) for all the traffic. It handles routing requests based on hostnames.</p></li></ol><pre><code><code>helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update
helm install nginx-ingress ingress-nginx/ingress-nginx `
--namespace ingress-nginx --create-namespace `
--set controller.replicaCount=1 `
--set controller.service.type=LoadBalancer `
--set controller.service.externalTrafficPolicy=Local `
--set controller.admissionWebhooks.enabled=false
</code></code></pre><p>Get Nginx controller public IP and set it in DNS registar</p><pre><code>kubectl get services -n ingress-nginx
NAME                                     TYPE           CLUSTER-IP     EXTERNAL-IP       PORT(S)                      AGE
nginx-ingress-ingress-nginx-controller   LoadBalancer   10.0.116.127   132.220.178.206   80:31906/TCP,443:31611/TCP   76s</code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xz17!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59250c51-2e8a-4c2f-9091-1bf22a49485d_1841x753.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xz17!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59250c51-2e8a-4c2f-9091-1bf22a49485d_1841x753.png 424w, https://substackcdn.com/image/fetch/$s_!xz17!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59250c51-2e8a-4c2f-9091-1bf22a49485d_1841x753.png 848w, https://substackcdn.com/image/fetch/$s_!xz17!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59250c51-2e8a-4c2f-9091-1bf22a49485d_1841x753.png 1272w, https://substackcdn.com/image/fetch/$s_!xz17!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59250c51-2e8a-4c2f-9091-1bf22a49485d_1841x753.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xz17!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59250c51-2e8a-4c2f-9091-1bf22a49485d_1841x753.png" width="1456" height="596" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/59250c51-2e8a-4c2f-9091-1bf22a49485d_1841x753.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:596,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:96625,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/176990147?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59250c51-2e8a-4c2f-9091-1bf22a49485d_1841x753.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xz17!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59250c51-2e8a-4c2f-9091-1bf22a49485d_1841x753.png 424w, https://substackcdn.com/image/fetch/$s_!xz17!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59250c51-2e8a-4c2f-9091-1bf22a49485d_1841x753.png 848w, https://substackcdn.com/image/fetch/$s_!xz17!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59250c51-2e8a-4c2f-9091-1bf22a49485d_1841x753.png 1272w, https://substackcdn.com/image/fetch/$s_!xz17!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59250c51-2e8a-4c2f-9091-1bf22a49485d_1841x753.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><ol start="2"><li><p><strong>Cert-Manager:</strong> This essential tool automates the provisioning, management, and renewal of TLS certificates from sources like Let&#8217;s Encrypt.</p></li></ol><pre><code><code>kubectl create namespace cert-manager
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install `
 cert-manager jetstack/cert-manager `
 --namespace cert-manager `
 --version v1.18.1 `
 --set installCRDs=true   
</code></code></pre><ol start="3"><li><p><strong>Kubrenetes cluster permissions to ACR:</strong>Make sure AKS cluster managed entity has ACRPull role assigned to Azure Container registry.</p></li></ol><pre><code>az aks update --resource-group &lt;RESOURCE_GROUP_NAME&gt; --name &lt;AKS_CLUSTER_NAME&gt; --attach-acr &lt;ACR_NAME&gt;</code></pre><ol start="4"><li><p><code>ClusterIssuer</code><strong> resource for </strong><code>cert-manager</code>:Its purpose is to obtain SSL/TLS certificates from Let&#8217;s Encrypt, using the HTTP-01 challenge, which is essential for enabling HTTPS on dev and prod Kubernetes services</p></li></ol><pre><code>apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    # The ACME server URL
    server: https://acme-v02.api.letsencrypt.org/directory
    # Email address used for ACME registration
    email: drvucanovic@gmail.com
    # Name of a secret used to store the ACME account private key
    privateKeySecretRef:
      name: letsencrypt-prod-account-key
    # Enable the HTTP-01 challenge mechanism
    solvers:
    - http01:
        ingress:
          class: nginx</code></pre><p></p><h4>Deploy to Dev Stage (<code>Deploy_to_dev</code>)</h4><p>This stage deploys the application to the <code>dev</code> namespace, making it accessible for testing and verification.</p><p><strong>Key Steps in the Dev Deployment:</strong></p><ol><li><p><strong>kubectl Installer:</strong> Ensures <code>kubectl</code> is available.</p></li><li><p><strong>Namespace Creation:</strong> Creates the <code>dev</code> namespace if it doesn&#8217;t already exist.</p></li><li><p><strong>Secrets Creation (</strong><code>app-config</code><strong>):</strong> Creates a Kubernetes Secret to hold sensitive application configurations (like database credentials).</p></li><li><p><strong>Helm Deployment (</strong><code>HelmDeploy@1</code><strong>):</strong></p><ul><li><p>This is the core of the deployment. It uses our Helm chart (<code>my-go-app-chart</code>) and the <code>values.dev.yaml</code> file.</p></li><li><p><strong>Crucially, this step triggers Cert-Manager.</strong> The <code>ingress.yaml</code> template, when rendered by Helm, contains annotations (<code>cert-manager.io/cluster-issuer</code>) and <code>tls</code> blocks that Cert-Manager watches. Upon detecting these, Cert-Manager automatically requests and stores the TLS certificate (<code>bigfirm-online-tls</code>) for <code>dev.bigfirm.online</code> in the <code>dev</code> namespace.</p></li></ul></li><li><p><strong>Deployment Restart:</strong> Performs a <code>kubectl rollout restart</code> to ensure the application deployment picks up any new image or secret changes.</p></li></ol><h4>Deploy to Production Stage (<code>Deploy_to_production</code>)</h4><p>This stage mirrors the Dev deployment but targets the <code>prod</code> namespace with production-specific configurations.<strong>Key Steps in the Production Deployment:</strong></p><ol><li><p><strong>kubectl Installer:</strong> Same as Dev.</p></li><li><p><strong>Namespace Creation:</strong> Creates the <code>prod</code> namespace.</p></li><li><p><strong>Secrets Creation (</strong><code>app-config</code><strong>):</strong> Creates production-specific secrets. <strong>Important:</strong> These should come from separate, more secure pipeline variables (<code>PROD_MYSQL_PASSWORD</code>, etc.) to maintain environment isolation.</p></li><li><p><strong>Helm Deployment (</strong><code>HelmDeploy@1</code><strong>):</strong></p><ul><li><p>Deploys the Helm chart using <code>values.prod.yaml</code>.</p></li><li><p>This file specifies <code>prod.bigfirm.online</code> as the production hostname and a dedicated TLS Secret name (<code>bigfirm-prod-tls</code>).</p></li><li><p>Again, <strong>Cert-Manager</strong> automatically provisions the TLS certificate for <code>prod.bigfirm.online</code> and stores it in <code>bigfirm-prod-tls</code> within the <code>prod</code> namespace. No manual certificate steps are needed!</p></li></ul></li><li><p><strong>Deployment Restart:</strong> Restarts the production Go application.</p></li></ol><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/building-a-robust-azure-devops-cicd?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/building-a-robust-azure-devops-cicd?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/building-a-robust-azure-devops-cicd/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/building-a-robust-azure-devops-cicd/comments"><span>Leave a comment</span></a></p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Using templates in AzureDevOps pipeline]]></title><description><![CDATA[One of the biggest challenges in maintaining Infrastructure as Code (IaC) pipelines is avoiding repetition.]]></description><link>https://adminjournal.substack.com/p/using-templates-in-azuredevops-pipeline</link><guid isPermaLink="false">https://adminjournal.substack.com/p/using-templates-in-azuredevops-pipeline</guid><dc:creator><![CDATA[Драган Вучановић]]></dc:creator><pubDate>Fri, 10 Oct 2025 09:42:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!kup-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9106abaa-8cfb-4c1c-8696-7e30b5e98a95_821x407.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kup-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9106abaa-8cfb-4c1c-8696-7e30b5e98a95_821x407.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kup-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9106abaa-8cfb-4c1c-8696-7e30b5e98a95_821x407.png 424w, https://substackcdn.com/image/fetch/$s_!kup-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9106abaa-8cfb-4c1c-8696-7e30b5e98a95_821x407.png 848w, https://substackcdn.com/image/fetch/$s_!kup-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9106abaa-8cfb-4c1c-8696-7e30b5e98a95_821x407.png 1272w, https://substackcdn.com/image/fetch/$s_!kup-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9106abaa-8cfb-4c1c-8696-7e30b5e98a95_821x407.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kup-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9106abaa-8cfb-4c1c-8696-7e30b5e98a95_821x407.png" width="821" height="407" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9106abaa-8cfb-4c1c-8696-7e30b5e98a95_821x407.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:407,&quot;width&quot;:821,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:354354,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/175785996?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9106abaa-8cfb-4c1c-8696-7e30b5e98a95_821x407.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kup-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9106abaa-8cfb-4c1c-8696-7e30b5e98a95_821x407.png 424w, https://substackcdn.com/image/fetch/$s_!kup-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9106abaa-8cfb-4c1c-8696-7e30b5e98a95_821x407.png 848w, https://substackcdn.com/image/fetch/$s_!kup-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9106abaa-8cfb-4c1c-8696-7e30b5e98a95_821x407.png 1272w, https://substackcdn.com/image/fetch/$s_!kup-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9106abaa-8cfb-4c1c-8696-7e30b5e98a95_821x407.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>One of the biggest challenges in maintaining Infrastructure as Code (IaC) pipelines is avoiding repetition. If you have five environments (Dev, QA, Staging, Prod-A, Prod-B), copying the 50-line Terraform Plan logic five times is a recipe for error.</p><p>The solution would be <strong>Azure DevOps YAML Stage Templates.</strong></p><p>This post breaks down a powerful, reusable, and secure pattern for running Terraform operations that only proceeds to the deployment stage if actual infrastructure changes are detected.</p><p>The main pipeline file<code> azure-pipelines.yml</code> serves as the &#8220;Table of Contents.&#8221; It sets global variables and, crucially, defines the <em>stages</em> by referencing templates. It passes dynamic information (like the working directory) to the reusable templates using <strong>parameters</strong>.</p><p><strong>Key Points:</strong></p><ul><li><p><strong>DRY Principle:</strong> We call a template, we don&#8217;t duplicate the steps.</p></li><li><p><strong>Variable vs. Parameter:</strong> We use <code>$(tfWorkingDir)</code> (a variable) in the main file and pass its value to the template using the <code>tfWorkingDir</code> parameter.</p></li><li><p><strong>Stage Dependency:</strong> The <code>Deploy</code> stage explicitly sets <code>dependsOnStage: Plan</code>, which we use in the template to enforce order.</p></li></ul><h3>Variables (<code>$()</code> syntax)</h3><ul><li><p>Variables are typically processed <strong>during the runtime</strong> of the pipeline (after the compilation/template expansion phase).</p></li><li><p>They are used for values that might change during the job execution (like iteration counts, file paths, or values set by previous tasks).</p></li><li><p>They are referenced using the <code>$(variableName)</code> syntax.</p></li><li><p><code>$(tfWorkingDir)</code> is defined in the <code>variables:</code> block of the main <code>azure-pipelines.yml</code>. It&#8217;s a pipeline-level setting that remains constant throughout the run, but YAML treats it as a runtime variable.</p></li></ul><h3>Parameters (<code>${{ }}</code> syntax)</h3><ul><li><p>Parameters are evaluated and substituted <strong>before the pipeline starts running</strong>, during a process called <strong>template expansion</strong> (or compilation). They are compile-time concepts.</p></li></ul><ul><li><p>They are essential for defining reusability and controlling the structure of the pipeline. They allow you to dynamically set job names, stage names, conditions, and other structural YAML elements.</p></li></ul><p>We cannot directly use a runtime variable (<code>$(tfWorkingDir)</code>) to define a compile-time structural element (like the <code>workingDirectory</code> of a task input within the template) because the compiler needs to know the final structure of the pipeline <em>before</em> any variables are resolved at runtime.</p><p><strong>The process works like this:</strong></p><ol><li><p><strong>Main File (</strong><code>azure-pipelines.yml</code><strong>):</strong> Passes the <em>value</em> of the variable <code>$(tfWorkingDir)</code> (which is '<code>app-service-and-sql-database'</code>) as an argument to the template&#8217;s parameter block:</p><p>YAML</p></li></ol><pre><code><code># Main File
- template: templates/terraform-plan-stage.yml
  parameters:
    tfWorkingDir: '$(tfWorkingDir)' # Passes the VALUE 'app-service-and-sql-database'
</code></code></pre><ol><li><p><strong>Template Expansion:</strong> Azure DevOps takes the value '<code>app-service-and-sql-database'</code> and substitutes it everywhere the parameter <code>${{ parameters.tfWorkingDir }}</code> is used in the template.</p></li><li><p><strong>Final Pipeline:</strong> The resulting, expanded YAML file (which is what actually runs) now has the hardcoded path where the parameter was used. This ensures the structural parts of the pipeline (like the artifact path or job inputs) are correctly defined before execution.</p></li></ol><h2><code>The Plan Template:templates/terraform-plan-stage.yml</code></h2><p>This template defines the entire <strong>Plan Stage</strong> logic, including initialization, planning, and, most critically, detecting changes.</p><h4>A. Parameters Block</h4><p>The template declares the inputs it expects from the orchestrator:</p><pre><code><code>parameters:
- name: stageName
  type: string
# ...
- name: tfWorkingDir
  type: string

</code></code></pre><h4>Conditional Output Variable</h4><p>The magic of conditional deployment happens here. We use a PowerShell task to execute <code>terraform show -json tfplan</code>, analyze the output for any resource changes (<code>create</code>, <code>update</code>, <code>delete</code>), and then set an <strong>output variable</strong>:</p><pre><code><code># Inside the PowerShell task:
script: |
  # ... logic to determine $anyTfChanges ...
  Write-Host &#8220;##vso[task.setvariable variable=anyTfChanges;isOutput=true]$anyTfChanges&#8221;
name: &#8216;SetChangesVariable&#8217;

</code></code></pre><p>This template runs the <code>terraform apply</code> command, but only if the previous <code>Plan</code> stage was successful and detected changes.</p><h2>The Deploy Template: <code>templates/terraform-deploy-stage.yml</code></h2><p>This template runs the <code>terraform apply</code> command, but only if the previous <code>Plan</code> stage was successful and detected changes.</p><p>Code is published on my <a href="https://github.com/dragan1979/azuredevops-terraform/tree/main">GitHub repo</a> and code is already explained  in my previous post,if you&#8217;re interested,check bellow text.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;3495f5f3-7d9f-4c19-8822-aa2ec842a519&quot;,&quot;caption&quot;:&quot;Example terraform file which deploy SQL server and Azure Windows services:&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;lg&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Terraform Pipelines in AzureDevOps&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:347763212,&quot;name&quot;:&quot;&#1044;&#1088;&#1072;&#1075;&#1072;&#1085; &#1042;&#1091;&#1095;&#1072;&#1085;&#1086;&#1074;&#1080;&#1115;&quot;,&quot;bio&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9bafe334-fcc5-4779-a993-d4250fdffd02_1080x1080.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2025-10-09T13:52:44.531Z&quot;,&quot;cover_image&quot;:&quot;https://substackcdn.com/image/fetch/$s_!1WWB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F905b27b0-936b-46cb-8bad-06ffb751011d_1127x438.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://adminjournal.substack.com/p/terraform-pipelines-in-azuredevops&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:175707766,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:5105485,&quot;publication_name&quot;:&quot;SysAdmin Journal&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!TdSv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5370a8c8-b0a2-410b-a666-a058413b87cd_1280x1280.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/using-templates-in-azuredevops-pipeline?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/using-templates-in-azuredevops-pipeline?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/using-templates-in-azuredevops-pipeline/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/using-templates-in-azuredevops-pipeline/comments"><span>Leave a comment</span></a></p><p></p><h3></h3>]]></content:encoded></item><item><title><![CDATA[Terraform Pipelines in AzureDevOps]]></title><description><![CDATA[Example terraform file which deploy SQL server and Azure Windows services:]]></description><link>https://adminjournal.substack.com/p/terraform-pipelines-in-azuredevops</link><guid isPermaLink="false">https://adminjournal.substack.com/p/terraform-pipelines-in-azuredevops</guid><dc:creator><![CDATA[Драган Вучановић]]></dc:creator><pubDate>Thu, 09 Oct 2025 13:52:44 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!1WWB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F905b27b0-936b-46cb-8bad-06ffb751011d_1127x438.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1WWB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F905b27b0-936b-46cb-8bad-06ffb751011d_1127x438.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1WWB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F905b27b0-936b-46cb-8bad-06ffb751011d_1127x438.png 424w, https://substackcdn.com/image/fetch/$s_!1WWB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F905b27b0-936b-46cb-8bad-06ffb751011d_1127x438.png 848w, https://substackcdn.com/image/fetch/$s_!1WWB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F905b27b0-936b-46cb-8bad-06ffb751011d_1127x438.png 1272w, https://substackcdn.com/image/fetch/$s_!1WWB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F905b27b0-936b-46cb-8bad-06ffb751011d_1127x438.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1WWB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F905b27b0-936b-46cb-8bad-06ffb751011d_1127x438.png" width="1127" height="438" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/905b27b0-936b-46cb-8bad-06ffb751011d_1127x438.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:438,&quot;width&quot;:1127,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:611600,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/175707766?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F905b27b0-936b-46cb-8bad-06ffb751011d_1127x438.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1WWB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F905b27b0-936b-46cb-8bad-06ffb751011d_1127x438.png 424w, https://substackcdn.com/image/fetch/$s_!1WWB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F905b27b0-936b-46cb-8bad-06ffb751011d_1127x438.png 848w, https://substackcdn.com/image/fetch/$s_!1WWB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F905b27b0-936b-46cb-8bad-06ffb751011d_1127x438.png 1272w, https://substackcdn.com/image/fetch/$s_!1WWB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F905b27b0-936b-46cb-8bad-06ffb751011d_1127x438.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Example terraform file which deploy SQL server and Azure Windows services:</p><p>main.tf</p><pre><code>terraform {
  required_providers {
    # 1. This is the resource provider namespace and name.
    azurerm = {
      source  = "hashicorp/azurerm"
      # 2. Specify a version constraint (use a recent version)
      version = "~&gt; 3.0&#8221;"
    }
    
  }
  }

provider "azurerm" {
  # This block is mandatory.
  # It tells Terraform how to configure the features of the AzureRM provider.
  features {}
}

resource "azurerm_resource_group" "RG-Terraform" {
  name     = &#8220;terraform-resource-group&#8221;
  location = &#8220;West Europe&#8221;
}

resource "azurerm_service_plan" "ASP-TerraForm" {
  name                = &#8220;terraform-appserviceplan&#8221;
  location            = azurerm_resource_group.RG-Terraform.location
  resource_group_name = azurerm_resource_group.RG-Terraform.name
 os_type             = &#8220;Windows&#8221;
  sku_name            = &#8220;P1v2&#8221;
}

resource "azurerm_windows_web_app" "AS-Terraform" {
  name                = "app-service-terraform-2027-10-08"
  location            = azurerm_resource_group.RG-Terraform.location
  resource_group_name = azurerm_resource_group.RG-Terraform.name
  service_plan_id = azurerm_service_plan.ASP-TerraForm.id
 
  
  site_config {}

  app_settings = {
    &#8220;SOME_KEY&#8221; = "some-value"
  }

  connection_string {
    name  = "Database"
    type  = "SQLServer"
    value = "Server=tcp:${azurerm_mssql_server.terraform-sqlserver.fully_qualified_domain_name} Database=${azurerm_mssql_database.terraform-sqldatabase.name};User ID=${azurerm_mssql_server.terraform-sqlserver.administrator_login};Password=${azurerm_mssql_server.terraform-sqlserver.administrator_login_password};Trusted_Connection=False;Encrypt=True;"
  }
}

resource &#8220;azurerm_mssql_server&#8221; "terraform-sqlserver" {
  name                         = "terraform-sqlserver"
  resource_group_name          = azurerm_resource_group.RG-Terraform.name
  location                     = azurerm_resource_group.RG-Terraform.location
  version                      = "12.0"
  administrator_login          = "houssem"
  administrator_login_password = "4-v3ry-53cr37-p455w0rd"
   minimum_tls_version          = "1.2"
}

resource "azurerm_mssql_database" "terraform-sqldatabase" {
  name                = "terraform-sqldatabase"
  server_id           = azurerm_mssql_server.terraform-sqlserver.id
  collation    = "SQL_Latin1_General_CP1_CI_AS"
  license_type = "LicenseIncluded"
  max_size_gb  = 2
  sku_name     = "S0"
  enclave_type = "VBS"
  tags = {
    environment = "production"
  }
}</code></pre><p>Terraform state file is stored in Azure storage account,in container tfstate, Azure DevOps ServiceConnection PrincipalID has Storage Blob Data Contributor role on the container where <code>terraform.tfstate</code> file is hosted.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2BJf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e16a48-f101-4427-baa6-6cb75a25b1ca_1208x210.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2BJf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e16a48-f101-4427-baa6-6cb75a25b1ca_1208x210.png 424w, https://substackcdn.com/image/fetch/$s_!2BJf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e16a48-f101-4427-baa6-6cb75a25b1ca_1208x210.png 848w, https://substackcdn.com/image/fetch/$s_!2BJf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e16a48-f101-4427-baa6-6cb75a25b1ca_1208x210.png 1272w, https://substackcdn.com/image/fetch/$s_!2BJf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e16a48-f101-4427-baa6-6cb75a25b1ca_1208x210.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2BJf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e16a48-f101-4427-baa6-6cb75a25b1ca_1208x210.png" width="1208" height="210" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a5e16a48-f101-4427-baa6-6cb75a25b1ca_1208x210.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:210,&quot;width&quot;:1208,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:27379,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/175707766?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e16a48-f101-4427-baa6-6cb75a25b1ca_1208x210.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2BJf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e16a48-f101-4427-baa6-6cb75a25b1ca_1208x210.png 424w, https://substackcdn.com/image/fetch/$s_!2BJf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e16a48-f101-4427-baa6-6cb75a25b1ca_1208x210.png 848w, https://substackcdn.com/image/fetch/$s_!2BJf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e16a48-f101-4427-baa6-6cb75a25b1ca_1208x210.png 1272w, https://substackcdn.com/image/fetch/$s_!2BJf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa5e16a48-f101-4427-baa6-6cb75a25b1ca_1208x210.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-bDx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff3f43b-d395-4d4c-a6b1-46aa1f29ef26_1567x99.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-bDx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff3f43b-d395-4d4c-a6b1-46aa1f29ef26_1567x99.png 424w, https://substackcdn.com/image/fetch/$s_!-bDx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff3f43b-d395-4d4c-a6b1-46aa1f29ef26_1567x99.png 848w, https://substackcdn.com/image/fetch/$s_!-bDx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff3f43b-d395-4d4c-a6b1-46aa1f29ef26_1567x99.png 1272w, https://substackcdn.com/image/fetch/$s_!-bDx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff3f43b-d395-4d4c-a6b1-46aa1f29ef26_1567x99.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-bDx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff3f43b-d395-4d4c-a6b1-46aa1f29ef26_1567x99.png" width="1456" height="92" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3ff3f43b-d395-4d4c-a6b1-46aa1f29ef26_1567x99.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:92,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:19006,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/175707766?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff3f43b-d395-4d4c-a6b1-46aa1f29ef26_1567x99.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-bDx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff3f43b-d395-4d4c-a6b1-46aa1f29ef26_1567x99.png 424w, https://substackcdn.com/image/fetch/$s_!-bDx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff3f43b-d395-4d4c-a6b1-46aa1f29ef26_1567x99.png 848w, https://substackcdn.com/image/fetch/$s_!-bDx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff3f43b-d395-4d4c-a6b1-46aa1f29ef26_1567x99.png 1272w, https://substackcdn.com/image/fetch/$s_!-bDx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ff3f43b-d395-4d4c-a6b1-46aa1f29ef26_1567x99.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p>This YAML file defines an <strong>Azure DevOps multi-stage pipeline</strong> for deploying infrastructure to <strong>Azure</strong> using <strong>Terraform</strong>. It implements a robust, two-stage <strong>Plan and Apply workflow</strong> that includes conditional deployment.</p><div><hr></div><h2>YAML Pipeline Description</h2><pre><code>pool:
  vmImage: 'ubuntu-latest'

variables:
  
  azureServiceConnectionName: '(1234ereee-daf0-etetttetec)'
  storageAccountResourceGroup: resourcegroup-tfstate
  storageAccountName: terraformstate20251009
  containerName: tfstate
  tfstateFile: terraform.tfstate
  tfWorkingDir: 'app-service-and-sql-database'

stages:
- stage: Plan
  displayName: 'Terraform Plan'
  jobs:
  - job: TerraformPlan
    displayName: 'Run Plan'
    
    steps:
      # 1. INSTALL TERRAFORM
      - task: ms-devlabs.custom-terraform-tasks.custom-terraform-installer-task.TerraformInstaller@0
        displayName: 'Install Terraform'
        inputs:
          terraformVersion: '1.13.3'
          
      # INIT AND PLAN (Combined and simplified script)
      - task: TerraformTaskV4@4
        displayName: 'Terraform Init'
        inputs:
          provider: 'azurerm'
          command: 'init'
          workingDirectory: '$(tfWorkingDir)'
          backendServiceArm: '$(azureServiceConnectionName)'
          backendAzureRmResourceGroupName: '$(storageAccountResourceGroup)'
          backendAzureRmStorageAccountName: '$(storageAccountName)'
          backendAzureRmContainerName: '$(containerName)'
          backendAzureRmKey: '$(tfstateFile)'
     
     # PLAN: Use the 'TerraformCLI' task for the plan command
      - task: TerraformTaskV4@4
        displayName: 'Terraform Plan'
        inputs:
          provider: 'azurerm'
          command: 'plan'
          workingDirectory: '$(tfWorkingDir)'
          backendServiceArm: '$(azureServiceConnectionName)'         
          environmentServiceNameAzureRM: '$(azureServiceConnectionName)'
          commandOptions: '-out=tfplan'
        name: 'TerraformPlanOutput'

      # CHECK PLAN OUTPUT FOR CHANGES AND SET A PIPELINE VARIABLE
      - task: PowerShell@2
        displayName: 'Detect Terraform Changes via JSON and Set Variable'
        inputs:
          # Use the correct working directory where tfplan resides:
          workingDirectory: '$(tfWorkingDir)'
          targetType: 'inline'
          script: |
            # Set initial variable value
            $anyTfChanges = "false&#8221;"

            # 1. Show the plan file and convert the output from JSON to a PowerShell object
            Write-Host &#8220;--- Running 'terraform show -json tfplan' ---&#8221;
            # Use -ErrorAction Stop to fail the script if 'tfplan' is missing or unreadable
            $plan = terraform show -json tfplan | ConvertFrom-Json -ErrorAction Stop
            
            # 2. Extract the list of unique actions (including 'replace')
            # Using Select-Object -Unique ensures each action type is listed only once.
            # Add 'replace' as it signifies a destroy/create change.
            $actions = $plan.resource_changes.change.actions | Select-Object -Unique
            
            # 3. Check for any action that indicates a change
            $hasChanges = $false
            if ($actions -contains 'create' -or $actions -contains 'delete' -or $actions -contains 'update' -or $actions -contains 'replace')
            {
              $hasChanges = $true
              $anyTfChanges = "true"
              # Join the unique actions array into a comma-separated string for a cleaner message
              $actionsString = $actions -join ', '
              Write-Host "Terraform changes detected! Actions: $actionsString"
            }
            else
            {
              Write-Host "No change detected in Terraform tfplan file."
            }
            
            # 4. Set the output variable
            Write-Host "--- Setting Pipeline Variable ---"
            Write-Host "##vso[task.setvariable variable=anyTfChanges;isOutput=true]$anyTfChanges"
            
            # 5. Output the final value for immediate verification
            Write-Host "SetChangesVariable.anyTfChanges is set to: $anyTfChanges"

          pwsh: true # Ensure PowerShell Core is used
        name: 'SetChangesVariable'
       

      # PUBLISH THE PLAN ARTIFACT (Required for the Apply stage)
      - publish: '$(tfWorkingDir)/tfplan'
        artifact: drop-tfplan
        displayName: 'Publish Plan Artifact
        # Publish only if changes exist
        condition: eq(variables['SetChangesVariable.anyTfChanges'], 'true')
       
          

- stage: Deploy
  displayName: 'Terraform Apply'
  dependsOn: Plan
  condition: and(succeeded('Plan'), eq(dependencies.Plan.outputs['TerraformPlan.SetChangesVariable.anyTfChanges'], 'true'))
  jobs:
  
  - job: TerraformApply
    displayName: 'Run Apply'
    steps:
      # 1. DOWNLOAD ARTIFACT
      - task: DownloadPipelineArtifact@2
        displayName: 'Download tfplan Artifact'
        inputs:
          artifactName: 'drop-tfplan'
          targetPath: '$(tfWorkingDir)'

      # INSTALL TERRAFORM
      - task: ms-devlabs.custom-terraform-tasks.custom-terraform-installer-task.TerraformInstaller@0
        displayName: 'Install Terraform'
        inputs:
          terraformVersion: '1.13.3'

      # ESTABLISH AZURE CREDENTIALS (Optional but safe)
      - task: AzureCLI@2
        displayName: 'Establish Azure Credentials (ARM_* variables)'
        inputs:
          azureSubscription: '$(azureServiceConnectionName)'
          scriptType: 'bash'
          scriptLocation: 'inlineScript'
          inlineScript: 'echo "Azure credentials re-established."'

      # TERRAFORM INIT
      - task: TerraformTaskV4@4
        displayName: 'Terraform Init for Apply'
        inputs:
          provider: 'azurerm'
          command: 'init'
          workingDirectory: '$(tfWorkingDir)'
          backendServiceArm: '$(azureServiceConnectionName)'
          backendAzureRmResourceGroupName: '$(storageAccountResourceGroup)'
          backendAzureRmStorageAccountName: '$(storageAccountName)'
          backendAzureRmContainerName: '$(containerName)'
          backendAzureRmKey: '$(tfstateFile)'

      # TERRAFORM APPLY
      - task: TerraformTaskV4@4
        displayName: 'Terraform Apply'
        inputs:
          provider: 'azurerm'
          command: 'apply'
          workingDirectory: '$(tfWorkingDir)'
          environmentServiceNameAzureRM: '$(azureServiceConnectionName)'
          commandOptions: 'tfplan'


      

</code></pre><p>The pipeline is structured into two main stages: <code>Plan</code> and <code>Deploy</code>.</p><h3>Global Configuration and Variables</h3><ul><li><p><code>pool: vmImage: 'ubuntu-latest'</code>: Specifies that all jobs will run on a Microsoft-hosted agent using the latest Ubuntu image.</p></li><li><p><code>variables:</code>: Defines reusable parameters, primarily for <strong>Azure Service Connection</strong> details and <strong>Terraform backend configuration</strong> (storing the state file in an Azure Storage Account, which is best practice).</p><ul><li><p>The <code>tfWorkingDir</code> variable points to the location of the Terraform configuration files ('<code>app-service-and-sql-database'</code>).</p></li></ul></li></ul><h3>Stage 1: Plan (<code>Plan</code>) </h3><p>This stage&#8217;s purpose is to install Terraform, initialize the backend, generate an execution plan, check if the plan contains any changes, and save the plan for the next stage.</p><ol><li><p><strong>Install Terraform</strong>: Uses the <code>TerraformInstaller@0</code> task to ensure the specific version (<code>1.13.3</code>) is available on the agent.</p></li><li><p><strong>Terraform Init</strong>: Uses <code>TerraformTaskV4@4</code> to run <code>terraform init</code>. This task downloads the Azure provider and configures the <strong>Azure Backend</strong> to manage the state file (<code>terraform.tfstate</code>) in the specified Azure Storage Account.</p></li><li><p><strong>Terraform Plan</strong>: Uses <code>TerraformTaskV4@4</code> to run <code>terraform plan</code> with the option <code>-out=tfplan</code>. This saves the proposed changes to a binary file named <code>tfplan</code>, ensuring the exact planned operations are used later for deployment.</p></li><li><p><strong>Detect Changes (PowerShell)</strong>: A <code>PowerShell@2</code> task runs <code>terraform show -json tfplan</code> to inspect the saved plan. It checks the resources for actions (<code>create</code>, <code>delete</code>, <code>update</code>, <code>replace</code>) and sets an <strong>output variable</strong> (<code>anyTfChanges</code>) to <code>true</code> or <code>false</code>.</p></li><li><p><strong>Publish Artifact</strong>: The <code>publish</code> task creates a pipeline artifact (<code>drop-tfplan</code>) containing the <code>tfplan</code> file. This step is <strong>conditional</strong> (<code>condition: eq(variables['SetChangesVariable.anyTfChanges'], 'true')</code>), meaning the plan artifact is only created if actual changes were detected.</p></li></ol><div><hr></div><h3>Stage 2: Deploy (<code>Deploy</code>)</h3><p>This stage&#8217;s purpose is to execute the deployment, but <strong>only if</strong> changes were detected in the <code>Plan</code> stage.</p><ul><li><p><strong>Conditional Execution</strong>: The entire stage runs only if the <code>Plan</code> stage succeeded <strong>AND</strong> the output variable from the Plan stage indicates changes:</p><p></p></li></ul><pre><code><code>condition: and(succeeded('Plan'), eq(dependencies.Plan.outputs['TerraformPlan.SetChangesVariable.anyTfChanges'], 'true'))
</code></code></pre><ul><li><p><strong>Download Artifact</strong>: Downloads the <code>tfplan</code> file created in the previous stage.</p></li><li><p><strong>Terraform Init (Again)</strong>: Re-initializes Terraform to ensure the backend and providers are correctly set up on the new agent running the <code>Deploy</code> job.</p></li><li><p><strong>Terraform Apply</strong>: Uses <code>TerraformTaskV4@4</code> to run <code>terraform apply</code>. Crucially, it uses <code>commandOptions: tfplan;</code> to apply the <strong>pre-approved and verified plan file</strong>, preventing any drift or unexpected changes since the plan was created.</p></li></ul><div><hr></div><h2>Why We Need Two <code>TerraformTaskV4@4</code> Tasks ?</h2><p>The reason is that <strong>Terraform commands are executed independently</strong> based on the <code>command:</code> input.</p><p>The two tasks perform two distinct, required steps in the standard Terraform workflow:</p><ol><li><p><code>TerraformTaskV4@4</code><strong> (for </strong><code>init</code><strong>)</strong>:</p><ul><li><p><strong>Command:</strong> <code>init</code></p></li><li><p><strong>Purpose:</strong> Initializes the Terraform working directory, downloads the necessary providers (for Azure in this case), and configures the <strong>remote backend</strong> (the Azure Storage Account). This must be done <strong>first</strong>.</p></li></ul></li><li><p><code>TerraformTaskV4@4</code><strong> (for </strong><code>plan</code><strong>)</strong>:</p><ul><li><p><strong>Command:</strong> <code>plan</code></p></li><li><p><strong>Purpose:</strong> Compares the desired state (your HCL code) with the current remote state in Azure, and generates a detailed execution plan. This cannot run until the directory is initialized.</p></li></ul></li></ol><p>It&#8217;s necessary to have a separate task for each command (<code>init</code> and <code>plan</code>) because the task is designed to wrap a single <code>terraform</code> command at a time. This modular approach is standard practice in CI/CD pipelines.</p><p><strong>This code is <a href="https://github.com/dragan1979/azuredevops-terraform">being re-factored</a> into AzureDevOps template,see bellow post:</strong></p><p></p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;03b797b8-f81a-495d-a2e2-3ad87d035ed1&quot;,&quot;caption&quot;:&quot;One of the biggest challenges in maintaining Infrastructure as Code (IaC) pipelines is avoiding repetition. If you have five environments (Dev, QA, Staging, Prod-A, Prod-B), copying the 50-line Terraform Plan logic five times is a recipe for error.&quot;,&quot;cta&quot;:&quot;Read full story&quot;,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;lg&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Using templates in AzureDevOps pipeline&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:347763212,&quot;name&quot;:&quot;&#1044;&#1088;&#1072;&#1075;&#1072;&#1085; &#1042;&#1091;&#1095;&#1072;&#1085;&#1086;&#1074;&#1080;&#1115;&quot;,&quot;bio&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9bafe334-fcc5-4779-a993-d4250fdffd02_1080x1080.png&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2025-10-10T09:42:25.009Z&quot;,&quot;cover_image&quot;:null,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://adminjournal.substack.com/p/using-templates-in-azuredevops-pipeline&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:175785996,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:5105485,&quot;publication_name&quot;:&quot;SysAdmin Journal&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/$s_!TdSv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5370a8c8-b0a2-410b-a666-a058413b87cd_1280x1280.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/terraform-pipelines-in-azuredevops?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/terraform-pipelines-in-azuredevops?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/terraform-pipelines-in-azuredevops/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/terraform-pipelines-in-azuredevops/comments"><span>Leave a comment</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Building a Modular Azure Deployment with Bicep: A Practical Guide]]></title><description><![CDATA[Bicep is a domain-specific language (DSL) for deploying Azure resources declaratively.]]></description><link>https://adminjournal.substack.com/p/building-a-modular-azure-deployment</link><guid isPermaLink="false">https://adminjournal.substack.com/p/building-a-modular-azure-deployment</guid><dc:creator><![CDATA[Драган Вучановић]]></dc:creator><pubDate>Thu, 11 Sep 2025 08:52:22 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!HTG1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920b97a9-2b7b-44b7-9659-beb7d2ec9187_1202x973.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HTG1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920b97a9-2b7b-44b7-9659-beb7d2ec9187_1202x973.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HTG1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920b97a9-2b7b-44b7-9659-beb7d2ec9187_1202x973.png 424w, https://substackcdn.com/image/fetch/$s_!HTG1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920b97a9-2b7b-44b7-9659-beb7d2ec9187_1202x973.png 848w, https://substackcdn.com/image/fetch/$s_!HTG1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920b97a9-2b7b-44b7-9659-beb7d2ec9187_1202x973.png 1272w, https://substackcdn.com/image/fetch/$s_!HTG1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920b97a9-2b7b-44b7-9659-beb7d2ec9187_1202x973.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HTG1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920b97a9-2b7b-44b7-9659-beb7d2ec9187_1202x973.png" width="1202" height="973" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/920b97a9-2b7b-44b7-9659-beb7d2ec9187_1202x973.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:973,&quot;width&quot;:1202,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:369918,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/173338368?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920b97a9-2b7b-44b7-9659-beb7d2ec9187_1202x973.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!HTG1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920b97a9-2b7b-44b7-9659-beb7d2ec9187_1202x973.png 424w, https://substackcdn.com/image/fetch/$s_!HTG1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920b97a9-2b7b-44b7-9659-beb7d2ec9187_1202x973.png 848w, https://substackcdn.com/image/fetch/$s_!HTG1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920b97a9-2b7b-44b7-9659-beb7d2ec9187_1202x973.png 1272w, https://substackcdn.com/image/fetch/$s_!HTG1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920b97a9-2b7b-44b7-9659-beb7d2ec9187_1202x973.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Bicep is a domain-specific language (DSL) for deploying Azure resources declaratively. It's a more readable and concise alternative to JSON-based Azure Resource Manager (ARM) templates.</p><h3>Why Use Bicep?</h3><p>You should use Bicep because it simplifies the process of authoring Infrastructure as Code (IaC) for Azure. Its key advantages include:</p><ul><li><p><strong>Simplified Syntax</strong>: Bicep's syntax is much cleaner and less verbose than ARM templates, which reduces boilerplate and makes your code easier to read and maintain. You can create resources without the repetitive <code>type</code>, <code>apiVersion</code>, and <code>properties</code> sections found in JSON.</p></li><li><p><strong>Modularity</strong>: Bicep makes it easy to break down large deployments into reusable modules. This promotes code reuse across projects, improves readability, and allows different team members to work on separate components without affecting the main template.</p></li><li><p><strong>Improved Safety</strong>: The Bicep VS Code extension provides a rich authoring experience with IntelliSense, syntax highlighting, and real-time validation. This allows you to catch errors and typos <em>before</em> you even run the deployment.</p></li><li><p><strong>Automatic Dependency Management</strong>: Bicep automatically detects and manages dependencies between resources. By referencing one resource in another (for example, a virtual machine using a virtual network's ID), Bicep understands the correct deployment order, eliminating the need for explicit <code>dependsOn</code> arrays.</p></li><li><p><strong>Ease of Adoption</strong>: You can decompile existing ARM templates into Bicep code using the Bicep CLI, making it easy to transition your current infrastructure and start using the new language.</p></li></ul><p></p><h2>Prerequisites</h2><h4><strong>Make sure you have Powershell 5.6.0 or higher</strong> (Check it with  <code>$PSVersionTable.PSVersion </code>command)</h4><p>If needed,install PowerShell 7:<code>winget install --id Microsoft.PowerShell --source winget</code></p><h4><strong>Install AZ module:</strong></h4><p><code>Install-module az</code></p><p><code>import-module az</code></p><p>Connect to Azure:</p><p><code>Connect-AzAccount</code></p><h4><a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/install">Install Bicep tool</a></h4><p>Not needed but,highly recommended,<a href="https://code.visualstudio.com/download">install VS code</a> and Bicep extension</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tAbb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabbe0a7c-8e0b-4870-8648-dbec0b2ef36f_1906x891.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tAbb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabbe0a7c-8e0b-4870-8648-dbec0b2ef36f_1906x891.png 424w, https://substackcdn.com/image/fetch/$s_!tAbb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabbe0a7c-8e0b-4870-8648-dbec0b2ef36f_1906x891.png 848w, https://substackcdn.com/image/fetch/$s_!tAbb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabbe0a7c-8e0b-4870-8648-dbec0b2ef36f_1906x891.png 1272w, https://substackcdn.com/image/fetch/$s_!tAbb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabbe0a7c-8e0b-4870-8648-dbec0b2ef36f_1906x891.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tAbb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabbe0a7c-8e0b-4870-8648-dbec0b2ef36f_1906x891.png" width="1456" height="681" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/abbe0a7c-8e0b-4870-8648-dbec0b2ef36f_1906x891.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:681,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:218271,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/173338368?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabbe0a7c-8e0b-4870-8648-dbec0b2ef36f_1906x891.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tAbb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabbe0a7c-8e0b-4870-8648-dbec0b2ef36f_1906x891.png 424w, https://substackcdn.com/image/fetch/$s_!tAbb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabbe0a7c-8e0b-4870-8648-dbec0b2ef36f_1906x891.png 848w, https://substackcdn.com/image/fetch/$s_!tAbb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabbe0a7c-8e0b-4870-8648-dbec0b2ef36f_1906x891.png 1272w, https://substackcdn.com/image/fetch/$s_!tAbb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fabbe0a7c-8e0b-4870-8648-dbec0b2ef36f_1906x891.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Bicep code is available <a href="https://github.com/dragan1979/bicep-azure">here</a>.</p><h3>What are Bicep Modules?</h3><p>Think of a Bicep module as a self-contained unit of deployment. It's a Bicep file (<code>.bicep</code>) that can be called from another Bicep file, known as the <strong>parent</strong> or <strong>root</strong> template. This approach promotes several key benefits:</p><ul><li><p><strong>Reusability:</strong> Write a module once and reuse it across multiple projects. For example, a module for a virtual network can be used in every deployment that requires one, ensuring consistency and saving time.</p></li><li><p><strong>Readability:</strong> Large, monolithic templates can be hard to read and understand. Modules help by logically organizing your code, making the main template easier to follow.</p></li><li><p><strong>Maintainability:</strong> Changes only need to be made in one place. If you need to update a resource configuration, you can modify the relevant module without touching the entire codebase.</p></li><li><p><strong>Reduced Complexity:</strong> By abstracting away the details of individual resource creation, the main template focuses on the overall architecture and how different components fit together.</p></li></ul><h3>Deconstructing a Bicep Deployment: A Practical Example</h3><p>Let's examine the <code>main.bicep</code> file you provided to see how these principles work in practice. The main file acts as an orchestrator, defining the overall architecture and calling individual modules for each major component.</p><div><hr></div><h3>&#128736;&#65039; The <code>main.bicep</code> Orchestrator</h3><p>The main file starts by defining <strong>parameters</strong> and <strong>variables</strong> that are passed down to the modules. This centralizes configuration and makes the deployment flexible. For instance, the <code>location</code> and <code>environment</code> parameters are used throughout the deployment.</p><pre><code><code>param location string = 'westeurope'
param environment string = 'dev'
// ... and many more
</code></code></pre><p>Next, it creates <strong>resource groups</strong> to logically organize the deployed resources. </p><pre><code><code>resource vnetRg 'Microsoft.Resources/resourceGroups@2021-04-01' = {
  name: vnetRgName
  location: location
}
// ... and other resource groups
</code></code></pre><h4>Calling the Modules</h4><p>The <code>main.bicep</code> file calls modules for each part of the infrastructure: a virtual network, a bastion host, a virtual machine, a key vault, and a load balancer.</p><p><strong>1. Virtual Network (VNet) Module</strong> &#127760;</p><p>The <code>vnetModule</code> call deploys the network infrastructure. Notice how the parent template simply passes parameters to the module without needing to know the low-level details of how the VNet and its subnets are created.</p><p>&#1060;&#1088;&#1072;&#1075;&#1084;&#1077;&#1085;&#1090; &#1082;&#1086;&#1076;&#1072;</p><pre><code><code>module vnetModule 'module/vnet.bicep' = {
  name: 'deployVNet'
  scope: resourceGroup(vnetRgName)
  params: {
    vnetName: vnetName
    // ... other parameters
    deployWANSubnet: deployWANSubnet
  }
  dependsOn: [
    vnetRg
  ]
}
</code></code></pre><p>The <code>dependsOn: [ vnetRg ]</code> line is crucial. It tells Bicep that the <code>vnetModule</code> deployment can't start until the <code>vnetRg</code> resource group has been successfully created. This establishes the correct deployment order.</p><p><strong>2. Bastion Host Module</strong> &#128274;</p><p>The <code>bastionModule</code> is called conditionally using an <code>if</code> statement. This demonstrates how modules can be deployed based on a parameter's value, making your templates even more dynamic.</p><pre><code><code>module bastionModule 'module/bastion.bicep' = if (deployBastionSubnet) {
  name: 'deployBastionHost'
  scope: resourceGroup(bastionRgName)
  params: {
    bastionSubnetID: vnetModule.outputs.bastionSubnetId
    // ... other parameters
  }
}
</code></code></pre><p>This module requires the <code>bastionSubnetId</code> from the VNet module. Bicep automatically understands this dependency, so the VNet module will always deploy first. The <code>vnetModule.outputs.bastionSubnetId</code> syntax is how a parent template accesses values exported by a module.</p><p>The same pattern is repeated for the other components:</p><ul><li><p><code>vmModule</code> deploys the virtual machines, also using a conditional <code>if</code> statement and a lookup map to get the correct subnet ID.</p></li><li><p><code>vaultModule</code> handles the Key Vault deployment, a standard practice for securely storing secrets.</p></li><li><p><code>balancerModule</code> deploys the load balancer, demonstrating how complex resources can be encapsulated in a single module.</p></li></ul><h4>Outputs</h4><p>Finally, the <code>main.bicep</code> file defines <strong>outputs</strong>, which allow the results of the deployment (like resource IDs or public IP addresses) to be returned to the user. This is particularly useful for scripting and automation.</p><pre><code><code>output vnetId string = vnetModule.outputs.vnetId
output bastionHostId string = deployBastionSubnet ? bastionModule.outputs.bastionHostId </code></code></pre><h3>Module for deploying an Azure Load Balancer</h3><p>This Bicep module provides a flexible and comprehensive solution for deploying an Azure Load Balancer. It is designed to be highly configurable, allowing you to define various aspects of your load balancer deployment, including the environment, project name, location, and key resource properties.</p><p>With this module, you can easily:</p><ul><li><p><strong>Create a Public IP Address</strong> and associate it with the load balancer.</p></li><li><p><strong>Define Load Balancing Rules</strong> for different ports and protocols, ensuring traffic is distributed effectively to your backend resources.</p></li><li><p><strong>Configure Health Probes</strong> to monitor the health of your backend instances, ensuring traffic is only sent to healthy virtual machines.</p></li><li><p><strong>Set up Inbound NAT Rules</strong> to map specific ports on the load balancer's public IP to individual virtual machines in the backend pool.</p></li></ul><p></p><h2>Module for Deploying Azure Bastion</h2><p> Azure Bastion provides a managed, secure, and seamless way to connect to your VMs directly from the Azure portal over a private network connection. The module creates two primary resources:</p><ul><li><p><strong>Public IP Address (</strong><code>bastionPublicIp</code><strong>)</strong>: Every Bastion Host requires a public IP address to allow secure communication from the Azure portal. This module automatically creates a <strong>Standard SKU Public IP</strong> with a static allocation method, which is a requirement for Bastion. It also uses the <code>zoneCount</code> parameter to make the IP address zone-redundant, matching the Bastion Host's availability settings.</p></li><li><p><strong>Bastion Host (</strong><code>bastionHost</code><strong>)</strong>: This is the core resource. It's configured to use the public IP address and the dedicated Bastion subnet provided as parameters. The <code>tags</code> variable ensures that the resource is properly labeled for your organization. The <code>ipConfigurations</code> property links the Bastion Host to the public IP address and the <code>AzureBastionSubnet</code>, establishing the network connectivity it needs to function.</p></li></ul><h4></h4><h2>Module for Deploying Azure Vault</h2><h3>&#128272; Secure by Default</h3><p>The module configures the Key Vault with <code>enableRbacAuthorization: true</code>, which uses Azure Role-Based Access Control instead of the older access policies model. This provides more granular control and aligns with Azure's recommended security practices. It also sets <code>defaultAction: 'Deny'</code> for network access, meaning only traffic from explicitly whitelisted IPs or trusted Azure services can connect to the vault.</p><h3>&#128101; Granular Access Control</h3><p>Instead of granting a single broad "Key Vault Administrator" role, the module assigns two more specific built-in roles to the specified <code>objectId</code>:</p><ul><li><p><strong>Key Vault Crypto Officer</strong>: Manages cryptographic keys.</p></li><li><p><strong>Key Vault Secrets Officer</strong>: Manages secrets.</p></li></ul><p>This follows the principle of least privilege, ensuring the principal only has the permissions it needs. The module also automatically assigns the required roles for <strong>Azure Disk Encryption</strong> to a fixed service principal, enabling it to access secrets and keys for encrypting virtual machine disks.</p><h3>&#128273; Secret Provisioning</h3><p>The module also provisions a new secret within the vault. The <code>secretName</code> and <code>secretValue</code> parameters allow you to create an initial secret as part of the deployment, which is a common practice for bootstrap configurations or storing initial credentials.</p><p></p><h3>Module for deploying Azure VM</h3><p>The module leverages Bicep's advanced features to create resources conditionally and dynamically:</p><ul><li><p><strong>Multiple VMs</strong>: The <code>numberOfVMs</code> parameter allows you to deploy multiple VMs using a single <code>for</code> loop. The module will create a corresponding VM, network interface, data disk, and public IP (if enabled) for each instance.</p></li><li><p><strong>Public IP Addresses</strong>: The <code>createPublicIp</code> boolean parameter determines whether a public IP address is provisioned and attached to the VM's network interface, giving you control over public exposure.</p></li><li><p><strong>OS-Specific Configuration</strong>: Using Bicep's <strong>ternary operators</strong> (<code>?:</code>), the module dynamically selects the correct OS image and profile settings (e.g., SSH key for Linux vs. password for Windows), reducing the need for separate templates.</p></li><li><p><strong>Availability Zones</strong>: The <code>zoneCount</code> parameter ensures VMs are distributed across availability zones for high availability and resilience. The <code>mod</code> operator (<code>%</code>) is used to cycle through the zones, distributing VMs evenly.</p></li></ul><div><hr></div><h3>Network Integration &amp; Load Balancer Support &#127760;</h3><p>The module seamlessly integrates the VMs into your existing network infrastructure:</p><ul><li><p><strong>Subnet Integration</strong>: It uses the <code>subnetId</code> parameter to place the VMs in a pre-existing subnet, ensuring they are part of your established virtual network.</p></li><li><p><strong>Load Balancer Backend Pool</strong>: The <code>loadBalancerBackendPoolId</code> parameter allows you to automatically add the VM's network interface to a load balancer backend pool. This is a crucial step for deploying web servers or other scalable applications behind a load balancer.</p></li></ul><h2>Module for deploying Virtual Network</h2><p>Using a set of boolean parameters (e.g., <code>deployWANSubnet</code>, <code>deployDMZSubnet</code>), you can choose which subnets to deploy. This allows you to use the same Bicep file to provision a wide range of network topologies, from a simple development environment with just a couple of subnets to a complete production environment with multiple security zones.</p><h3>&#128272; Automated Security with NSGs</h3><p>The module enforces a secure, multi-tier architecture by automatically creating and associating Network Security Groups (NSGs) with each deployed subnet. The NSGs come pre-configured with a set of security rules that define the flow of traffic between the different tiers. This ensures that:</p><ul><li><p><strong>WAN Subnet</strong> can be accessed from the Management subnet for administrative purposes.</p></li><li><p><strong>DMZ Subnet</strong> is exposed to the internet for public-facing services (e.g., web servers).</p></li><li><p><strong>App Subnet</strong> can only receive traffic from the DMZ.</p></li><li><p><strong>Database Subnet</strong> can only be accessed from the App subnet.</p></li></ul><p>This "deny-by-default" approach ensures that traffic is strictly controlled, significantly reducing your attack surface. It also includes specific rules to allow connections from a conditionally deployed <code>AzureBastionSubnet</code> for secure remote access.</p><h3></h3><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading SysAdmin Journal! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/building-a-modular-azure-deployment/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/building-a-modular-azure-deployment/comments"><span>Leave a comment</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/building-a-modular-azure-deployment?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/building-a-modular-azure-deployment?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p>]]></content:encoded></item><item><title><![CDATA[Deploying Wordpress on Azure Kubernetes]]></title><description><![CDATA[In this WordPress deployment on Kubernetes, an Azure Private Endpoint is used to enhance the security and connectivity of the Azure Database for MySQL Flexible Server.Let&#8217;s encrypt SSL cert is assigned to wodpress instance.]]></description><link>https://adminjournal.substack.com/p/deploying-wordpress-on-azure-kubernetes</link><guid isPermaLink="false">https://adminjournal.substack.com/p/deploying-wordpress-on-azure-kubernetes</guid><dc:creator><![CDATA[Драган Вучановић]]></dc:creator><pubDate>Thu, 03 Jul 2025 10:47:50 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!a2ev!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636c1ad1-e7c1-4435-ba7e-4f9c545a66cc_1203x964.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!a2ev!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636c1ad1-e7c1-4435-ba7e-4f9c545a66cc_1203x964.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!a2ev!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636c1ad1-e7c1-4435-ba7e-4f9c545a66cc_1203x964.png 424w, https://substackcdn.com/image/fetch/$s_!a2ev!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636c1ad1-e7c1-4435-ba7e-4f9c545a66cc_1203x964.png 848w, https://substackcdn.com/image/fetch/$s_!a2ev!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636c1ad1-e7c1-4435-ba7e-4f9c545a66cc_1203x964.png 1272w, https://substackcdn.com/image/fetch/$s_!a2ev!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636c1ad1-e7c1-4435-ba7e-4f9c545a66cc_1203x964.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!a2ev!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636c1ad1-e7c1-4435-ba7e-4f9c545a66cc_1203x964.png" width="1203" height="964" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/636c1ad1-e7c1-4435-ba7e-4f9c545a66cc_1203x964.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:964,&quot;width&quot;:1203,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:510114,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/167425297?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636c1ad1-e7c1-4435-ba7e-4f9c545a66cc_1203x964.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!a2ev!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636c1ad1-e7c1-4435-ba7e-4f9c545a66cc_1203x964.png 424w, https://substackcdn.com/image/fetch/$s_!a2ev!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636c1ad1-e7c1-4435-ba7e-4f9c545a66cc_1203x964.png 848w, https://substackcdn.com/image/fetch/$s_!a2ev!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636c1ad1-e7c1-4435-ba7e-4f9c545a66cc_1203x964.png 1272w, https://substackcdn.com/image/fetch/$s_!a2ev!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636c1ad1-e7c1-4435-ba7e-4f9c545a66cc_1203x964.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In this WordPress deployment on Kubernetes, an Azure Private Endpoint is used to enhance the security and connectivity of the Azure Database for MySQL Flexible Server.Let&#8217;s encrypt SSL cert is assigned to wodpress instance.</p><p>Here's why Private Endpoint was used:</p><ul><li><p><strong>Secure Connectivity:</strong> A Private Endpoint provides a private IP address for Azure MySQL Flexible Server within your Azure Virtual Network (VNet). This means that traffic between AKS cluster (which is integrated into the same VNet) and the MySQL database travels entirely within the Microsoft Azure backbone network, rather than over the public internet.</p></li><li><p><strong>Reduced Data Exfiltration Risk:</strong> By keeping database traffic private, it significantly reduces the risk of data exfiltration and provides a more isolated and secure environment for your sensitive database.</p></li><li><p><strong>Simplified Network Configuration:</strong> It simplifies your network architecture by removing the need for public IP addresses or complex firewall rules to access database from within VNet.</p></li></ul><p><strong>Private DNS zone:</strong></p><p>Is used to enable secure, private connections to the backend Azure Database for MySQL.</p><ul><li><p>When we secure your Azure database instance using a <strong>Private Endpoint</strong>, that endpoint is only accessible via a private IP address within Azure Virtual Network (VNet).</p></li><li><p><strong>Name Resolution:</strong> The database service must resolve to that private IP address, not the public one. A Private DNS Zone is the authoritative source for this private name resolution. It contains the necessary &#8220;A&#8221; records to tell the Pods in AKS cluster (where WordPress runs) the correct private IP for the database.</p></li></ul><p>Without the Private DNS Zone, WordPress Pods would try to resolve the database name publicly, fail to connect over the private network, or potentially connect to a public endpoint if one is available, which is highly insecure.</p><p>Using Azure Database for MySQL Flexible Server offers several significant advantages over deploying MySQL as a Kubernetes pod directly within cluster, particularly for production-grade WordPress deployments:</p><ol><li><p><strong>Reduced Operational Overhead:</strong></p><ul><li><p><strong>Managed Service:</strong> Azure handles routine database administration tasks such as patching, backups, security updates, monitoring, and scaling. If we were running MySQL in a Kubernetes pod, we would be responsible for all these tasks, requiring significant expertise and effort.</p></li><li><p><strong>No Kubernetes Complexity for Database:</strong> Managing stateful applications like databases in Kubernetes can be complex (e.g., persistent volumes, stateful sets, upgrades, replication). A managed service abstracts this complexity.</p></li></ul></li><li><p><strong>Built-in High Availability and Disaster Recovery:</strong></p><ul><li><p>Azure MySQL Flexible Server offers built-in high availability with automatic failover to a hot standby in a different availability zone (or within the same zone), ensuring database remains accessible even during infrastructure failures.</p></li><li><p>Automated backups with point-in-time restore capabilities provide robust disaster recovery. Replicating a production-ready HA/DR setup for MySQL within Kubernetes would be a substantial engineering effort.</p></li></ul></li><li><p><strong>Scalability and Performance:</strong></p><ul><li><p>Flexible Server is designed for scalable performance, allowing  easily scale compute (vCores) and storage independently, often with minimal downtime.</p></li><li><p>It's optimized for database workloads, potentially offering better performance than a generic pod running on a shared Kubernetes node.</p></li></ul></li><li><p><strong>Enhanced Security and Isolation:</strong></p><ul><li><p>As highlighted before, using a private endpoint with Flexible Server ensures that traffic between AKS cluster and the database travels over Azure's private backbone network, significantly reducing exposure to the public internet and enhancing data security.</p></li><li><p>Azure applies security best practices and compliance certifications to its managed services.</p></li></ul></li><li><p><strong>Cost Efficiency (Total Cost of Ownership):</strong></p><ul><li><p>While there's a direct cost for the managed service, the total cost of ownership (TCO) can be lower due to reduced operational effort, less need for specialized database administrators, and optimized resource utilization compared to self-managing a highly available MySQL cluster on Kubernetes.</p></li></ul></li></ol><p>Code can be found <a href="https://github.com/dragan1979/kubernetes-azure/">here</a>.</p><ul><li><p><code>cluster-issuer.yaml</code>: This file defines a <code>ClusterIssuer</code> resource for <code>cert-manager</code>. Its purpose is to obtain SSL/TLS certificates from Let's Encrypt, using the HTTP-01 challenge, which is essential for enabling HTTPS on your WordPress site.</p></li><li><p><code>mysql-azure-secret.yaml</code>: This file contains two Kubernetes <code>Secret</code> resources. One secret (<code>wordpress-azure-mysql-secret</code>) stores sensitive connection details for your Azure MySQL Flexible Server, including the host, username, password, and database name. The other secret (<code>wordpress-auth-secret</code>) stores WordPress authentication unique keys and salts.</p></li><li><p><code>wordpress-config-map.yml</code>: This file defines a <code>ConfigMap</code> named <code>php-config</code>. It holds custom PHP settings such as <code>upload_max_filesize</code>, <code>memory_limit</code>, and <code>max_execution_time</code>, which are applied to the WordPress pods.</p></li><li><p><code>wordpress-deployment.yaml</code>: This file defines the Kubernetes <code>Deployment</code> for the WordPress application. It specifies that 3 replicas of the WordPress pod should be created, includes an <code>initContainer</code> to correct permissions on the <code>wp-content</code> directory, mounts persistent storage and the PHP configuration, and injects database credentials and WordPress authentication salts as environment variables.</p></li><li><p><code>wordpress-files-pvc.yaml</code>: This file defines both a <code>StorageClass</code> and a <code>PersistentVolumeClaim</code> (PVC) for WordPress. The <code>StorageClass</code> (<code>azurefile-wordpress</code>) configures Azure Files to allow multiple WordPress pods to share the same <code>wp-content</code> directory (<code>ReadWriteMany</code> access mode). The <code>PersistentVolumeClaim</code> (<code>wordpress-content-pvc</code>) requests 5Gi of storage for the <code>wp-content</code> directory.</p></li><li><p><code>wordpress-ingress.yaml</code>: This file defines the Kubernetes <code>Ingress</code> resource. It configures NGINX Ingress to direct external traffic to the <code>wordpress-service</code>, automatically provisions a TLS certificate for <code>blog.bigfirm.online</code> using <code>cert-manager</code>, enforces SSL redirection, and sets proxy timeouts and body size limits.</p></li><li><p><code>wordpress-service.yaml</code>: This file defines a Kubernetes <code>Service</code> of type <code>ClusterIP</code> for the WordPress deployment. This service exposes port 80 internally within the cluster, allowing the Ingress controller to forward traffic to the WordPress pods.</p></li></ul><p>When trying to secure WordPress with Let's Encrypt, i encountered a common hurdle: certificate issuance failures. A key step in resolving this involved a seemingly small but impactful flag during NGINX Ingress Controller installation: <code>--set controller.admissionWebhooks.enabled=false</code>. This setting disables the Ingress controller's admission webhooks, which are typically responsible for validating and mutating Kubernetes Ingress resources. In this case, disabling them removed a potential conflict point, allowing Cert-Manager to successfully create its temporary Ingress resources for the HTTP-01 challenge and obtain our SSL certificates. While admission webhooks offer valuable validation, understanding when and why to temporarily disable them can be a crucial troubleshooting technique in complex Kubernetes deployments."</p><p>After provisioning Let&#8217;s encrypt SSL cert<code> kubectl apply -f wordpress-ingress.yaml -n wordpress, </code>monitor cert deloyment:</p><p>If cert was not issues, ran below commands:</p><pre><code># Check if the Cert-Manager pods are running,You should see cert-manager, cert-# manager-cainjector, and cert-manager-webhook pods.
kubectl get pods -n cert-manager
# Check cert status
kubectl get certificate -n wordpress
kubectl describe certificate blog-bigifirm-online-tls -n wordpress
# Check cert request status
kubectl get certificaterequest -n wordpress
# Check cert order status
kubectl get order -n wordpress
# Most important, check challenge status,it will tell why cert has not been issued
kubectl get challenges -n wordpress
kubectl describe challenge &lt;challenge-name&gt; -n wordpress
# If all is fine, you'll get as below
kubectl get certificate -n wordpress
NAME                      READY   SECRET                    AGE
blog-bigfirm-online-tls   True    blog-bigfirm-online-tls   3m2s
</code></pre><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading SysAdmin Journal! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/deploying-wordpress-on-azure-kubernetes?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/deploying-wordpress-on-azure-kubernetes?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/deploying-wordpress-on-azure-kubernetes/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/deploying-wordpress-on-azure-kubernetes/comments"><span>Leave a comment</span></a></p>]]></content:encoded></item><item><title><![CDATA[Monitoring Log Files with PowerShell and Zabbix]]></title><description><![CDATA[Following PowerShell script monitors various log files and sends output to JSON file, due to large number of logs, although script executes for about 16 seconds, was getting &#8220;Timed out&#8221; errors in Zabbix, that&#8217;s why output is saved in file.Each line in log file starts with datetime stamp, for example:]]></description><link>https://adminjournal.substack.com/p/monitoring-log-files-with-powershell</link><guid isPermaLink="false">https://adminjournal.substack.com/p/monitoring-log-files-with-powershell</guid><dc:creator><![CDATA[Драган Вучановић]]></dc:creator><pubDate>Fri, 27 Jun 2025 10:40:11 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!3034!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f178fa2-85ff-403f-8aec-9c7fea4cf96d_891x778.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3034!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f178fa2-85ff-403f-8aec-9c7fea4cf96d_891x778.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3034!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f178fa2-85ff-403f-8aec-9c7fea4cf96d_891x778.png 424w, https://substackcdn.com/image/fetch/$s_!3034!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f178fa2-85ff-403f-8aec-9c7fea4cf96d_891x778.png 848w, https://substackcdn.com/image/fetch/$s_!3034!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f178fa2-85ff-403f-8aec-9c7fea4cf96d_891x778.png 1272w, https://substackcdn.com/image/fetch/$s_!3034!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f178fa2-85ff-403f-8aec-9c7fea4cf96d_891x778.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3034!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f178fa2-85ff-403f-8aec-9c7fea4cf96d_891x778.png" width="891" height="778" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1f178fa2-85ff-403f-8aec-9c7fea4cf96d_891x778.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:778,&quot;width&quot;:891,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:299559,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/166961305?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f178fa2-85ff-403f-8aec-9c7fea4cf96d_891x778.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!3034!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f178fa2-85ff-403f-8aec-9c7fea4cf96d_891x778.png 424w, https://substackcdn.com/image/fetch/$s_!3034!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f178fa2-85ff-403f-8aec-9c7fea4cf96d_891x778.png 848w, https://substackcdn.com/image/fetch/$s_!3034!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f178fa2-85ff-403f-8aec-9c7fea4cf96d_891x778.png 1272w, https://substackcdn.com/image/fetch/$s_!3034!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f178fa2-85ff-403f-8aec-9c7fea4cf96d_891x778.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Following PowerShell script monitors various log files and sends output to JSON file, due to large number of logs, although script executes for about 16 seconds, was getting &#8220;Timed out&#8221; errors in Zabbix, that&#8217;s why output is saved in file.Each line in log file starts with datetime stamp, for example:</p><p><code>2025.06.27 12:35:12&#9;Attempting to fetch Azure AD audit sign-in logs for</code></p><p>Script search log file section created last time log was modified: if last time script was running today, it will search today&#8217;s date, if yesterday, then yesterday&#8217;s date and so on.</p><pre><code># Script for monitoring varius log files and sending results
# to JSON file which is send to Zabbix



# Define the log file for THIS script's errors (for the WriteLog function)
$log = "D:\ScriptsLogs\CheckLogErrorsForZabbix.txt"

# Define the array of log file paths to scan.
$LogFiles = @(
    "D:\ScriptsLogs\1.txt",
    "D:\ScriptsLogs\2.txt",
    "D:\ScriptsLogs\3.txt",
    "D:\ScriptsLogs\4.txt"
)

$SearchStrings = @(
    "error",
    "exception",
    "[ERROR]",
    "Exception calling"
)

# Define a BASE set of ignore patterns (these apply to ALL files)
$BaseIgnorePatterns = @(
    "Could not get FGPP for"
    "Insufficient access a to perform the operation"
    "Insufficient access rights to perform the operation"
    "Cannot find an object with identity"
    # Add other truly global ignore patterns here
)

# Define a Hashtable for file-specific ignore patterns.
# Key: Full path to the log file.
# Value: Array of strings to ignore ONLY for that specific file.
$FileSpecificIgnorePatternsMap = @{
    "D:\ScriptsLogs\1.txt" = @(
        "More than one contract"
    );
    # Add more file paths and their specific literal ignore patterns here as needed
}

# Define the path where the JSON output file will be saved
$JsonOutputFilePath = "D:\ScriptsLogs\ZabbixLogErrors.json"

# Compile search patterns into a single regex object
$combinedSearchRegexPattern = ($SearchStrings | ForEach-Object { [regex]::Escape($_) }) -join '|'

# Regex to match the date part at the very beginning of a line (e.g., 2025.06.24)
# Also allows for timestamp and then a space or tab, and captures the date itself in group 1.
$dateLineRegex = '^(\d{4}\.\d{2}\.\d{2})(?:\s+\d{2}:\d{2}:\d{2})?[\s\t]*'

# Array to store results for Zabbix - Keep this OUTSIDE the loop
$zabbixResults = @()

# region --- Main Processing Loop ---

foreach ($logFilePath in $LogFiles) {
    # Initialize a temporary result object for current file's processing status
    # This object holds the actual analysis results (status, message, date)
    $currentFileAnalysisResult = [PSCustomObject]@{
        "status"           = 0 # Default: No error found
        "latest_error_message" = ""
        "latest_error_date"    = ""
    }

    if (-not (Test-Path -LiteralPath $logFilePath -PathType Leaf)) {
        $currentFileAnalysisResult.status = 0
        $currentFileAnalysisResult.latest_error_message = "Log file not found: $logFilePath"
        $currentFileAnalysisResult.latest_error_date = (Get-Date -Format 'yyyy.MM.dd')
        WriteLog "Warning: Log file not found - $logFilePath" $log # Log this specific warning
    } else {
        # --- Step 1: Initialize current file's ignore patterns with base patterns ---
        $currentFileIgnorePatterns = [System.Collections.ArrayList]::new($BaseIgnorePatterns)

        # --- Step 2: Add file-specific ignore patterns from the map ---
        if ($FileSpecificIgnorePatternsMap.ContainsKey($logFilePath)) {
            $patternsToAdd = $FileSpecificIgnorePatternsMap[$logFilePath]
            foreach ($pattern in $patternsToAdd) {
                $currentFileIgnorePatterns.Add($pattern) | Out-Null
            }
        }

        # --- Step 3: Compile the combined ignore regex pattern for the *current file* ---
        $combinedIgnoreRegexPattern = ($currentFileIgnorePatterns | ForEach-Object { [regex]::Escape($_) }) -join '|'

        $latestDateInFile = $null # Stores the most recent date found in the current log file

        # --- Pass 1: Determine the absolute latest date in the file ---
        try {
            $reader = [System.IO.File]::OpenText($logFilePath)
            while (($line = $reader.ReadLine()) -ne $null) {
                if ($line -match $dateLineRegex) {
                    $lineDate = $Matches[1]
                    if ($latestDateInFile -eq $null -or $lineDate -gt $latestDateInFile) {
                        $latestDateInFile = $lineDate
                    }
                }
            }
            $reader.Close()
        } catch {
            $currentFileAnalysisResult.status = 0
            $currentFileAnalysisResult.latest_error_message = "Script Error (Pass 1) for $logFilePath - $($_.Exception.Message)"
            $currentFileAnalysisResult.latest_error_date = (Get-Date -Format 'yyyy.MM.dd')
            WriteLog "Error (Pass 1) for $logFilePath $($_.Exception.Message)" $log # Corrected WriteLog call
        }

        # Only proceed to Pass 2 if no errors occurred in Pass 1 and dates were found
        if ($currentFileAnalysisResult.latest_error_message -eq "" -and $latestDateInFile -eq $null) {
            # No date-stamped entries found, so no errors to report for this file
            $currentFileAnalysisResult.status = 0
            $currentFileAnalysisResult.latest_error_message = "No date-stamped entries found."
            $currentFileAnalysisResult.latest_error_date = (Get-Date -Format 'yyyy.MM.dd')
        } elseif ($currentFileAnalysisResult.latest_error_message -eq "") { # If no errors in Pass 1 and date found
            # --- Pass 2: Collect all entries for the determined latest date and process ---
            try {
                $entriesForTargetDate = [System.Collections.ArrayList]::new()
                $currentEntryLines = [System.Collections.ArrayList]::new()
                $collectingForTargetDate = $false

                $reader = [System.IO.File]::OpenText($logFilePath)
                while (($line = $reader.ReadLine()) -ne $null) {
                    if ($line -match $dateLineRegex) {
                        $lineDate = $Matches[1]
                        if ($lineDate -eq $latestDateInFile) {
                            if ($currentEntryLines.Count -gt 0) {
                                $entriesForTargetDate.Add(($currentEntryLines -join "`n")) | Out-Null
                                $currentEntryLines.Clear()
                            }
                            $currentEntryLines.Add($line) | Out-Null
                            $collectingForTargetDate = $true
                        } elseif ($collectingForTargetDate -and $lineDate -lt $latestDateInFile) {
                            if ($currentEntryLines.Count -gt 0) {
                                $entriesForTargetDate.Add(($currentEntryLines -join "`n")) | Out-Null
                            }
                            $collectingForTargetDate = $false
                            break
                        } else {
                            $currentEntryLines.Clear()
                            $collectingForTargetDate = $false
                        }
                    } elseif ($collectingForTargetDate) {
                        $currentEntryLines.Add($line) | Out-Null
                    }
                }
                $reader.Close()

                if ($currentEntryLines.Count -gt 0) {
                    $entriesForTargetDate.Add(($currentEntryLines -join "`n")) | Out-Null
                }

                $latestError = $null

                # Process entries in reverse order to find the latest non-ignored error
                for ($i = $entriesForTargetDate.Count - 1; $i -ge 0; $i--) {
                    $entry = $entriesForTargetDate[$i]
                    if ($entry -match $combinedIgnoreRegexPattern) {
                        continue
                    }
                    # Check if this entry matches any search pattern
                    if ($entry -match $combinedSearchRegexPattern) {
                        $latestError = $entry
                        break
                    }
                }

                if ($latestError) {
                    $firstLineOfError = $latestError.Split("`n")[0]
                    $currentFileAnalysisResult.status = 1
                    $currentFileAnalysisResult.latest_error_message = $firstLineOfError
                    $currentFileAnalysisResult.latest_error_date = $latestDateInFile
                } else {
                    $currentFileAnalysisResult.status = 0
                    $currentFileAnalysisResult.latest_error_message = ""
                    $currentFileAnalysisResult.latest_error_date = $latestDateInFile
                }

            } catch {
                $errorMessage = $_.Exception.Message
                if ($errorMessage -isnot [string]) {
                    $errorMessage = $errorMessage.ToString()
                }
                $currentFileAnalysisResult.status = 0
                $currentFileAnalysisResult.latest_error_message = "Script Error (Pass 2) for $logFilePath - $errorMessage"
                $currentFileAnalysisResult.latest_error_date = (Get-Date -Format 'yyyy.MM.dd')
                WriteLog "Error (Pass 2) for $logFilePath $($_.Exception.Message)" $log # Corrected WriteLog call
            }
        }
    }

    # After all processing for the current logFilePath is done,
    # create the final result object with the correct Zabbix macro and collected data.
    $fileName = (Get-Item $logFilePath).Name # Extract filename here

    $finalZabbixEntry = [PSCustomObject]@{
        "{#LOGFILE_NAME}"       = $fileName
        "original_path"          = $logFilePath # Optional: useful for troubleshooting in Zabbix GUI
        "status"                 = $currentFileAnalysisResult.status
        "latest_error_message"   = $currentFileAnalysisResult.latest_error_message
        "latest_error_date"      = $currentFileAnalysisResult.latest_error_date
    }

    # Add the result for the current file to the overall results array
    $zabbixResults += $finalZabbixEntry
}

# endregion

# region --- Save Zabbix Output to File ---

# Format the results as JSON
$zabbixOutput = @{
    "data" = $zabbixResults
} | ConvertTo-Json -Depth 100

# Save the JSON to the specified file path
try {
    # Ensure the directory exists
    $OutputDirectory = Split-Path $JsonOutputFilePath
    if (-not (Test-Path -LiteralPath $OutputDirectory -PathType Container)) {
        New-Item -Path $OutputDirectory -ItemType Directory -Force | Out-Null
    }
   $zabbixOutput | Out-File $JsonOutputFilePath -Encoding UTF8 -Force
    # Optionally, you can add a log entry here if you have a WriteLog function
    WriteLog "JSON output successfully saved to $JsonOutputFilePath" $log # Corrected WriteLog call
} catch {
    # Write to standard error if saving fails (Zabbix won't see this, but it helps debugging scheduled task)
    Write-Error "Failed to save JSON output to $JsonOutputFilePath $($_.Exception.Message)"
    WriteLog "CRITICAL: Failed to save JSON output to $JsonOutputFilePath $($_.Exception.Message)" $log
}
</code></pre><p>The script uses a two-pass approach for processing each log file primarily to ensure that it only reports the <em>latest</em> relevant error from the <em>latest</em> date present in the log file.</p><ol><li><p><strong>Pass 1: Determine the Absolute Latest Date in the File</strong></p><ul><li><p>The first pass reads through the entire log file to identify the most recent date stamp present in any log entry.</p></li><li><p>It uses the <code>$dateLineRegex</code> to find lines starting with a date (e.g., "YYYY.MM.DD").</p></li><li><p>The purpose of this pass is to establish a temporal context. If a log file contains entries from multiple days, the script is only interested in potential errors that occurred on the very last day activity was recorded. This prevents it from reporting old, resolved errors.</p></li></ul></li><li><p><strong>Pass 2: Collect and Process Entries for the Determined Latest Date</strong></p><ul><li><p>Once the <code>latestDateInFile</code> is determined, the second pass reads the log file again.</p></li><li><p>This time, it collects <em>all</em> log entries (potentially multi-line entries) that correspond to the <code>latestDateInFile</code>.</p></li><li><p>It then processes these collected entries in reverse chronological order (from newest to oldest).</p></li><li><p>For each entry on the latest date, it first checks if the entry matches any of the <code>combinedIgnoreRegexPattern</code> (base or file-specific). If it does, the entry is skipped.</p></li><li><p>If the entry is not ignored, it then checks if it matches any of the <code>combinedSearchRegexPattern</code> (error/exception keywords).</p></li><li><p>The <em>first</em> error found in this reverse search (meaning the latest non-ignored error on the latest date) is then captured as the <code>latest_error_message</code>.</p></li><li><p>If no errors are found for the latest date after filtering, the status remains clear.</p></li></ul></li></ol><h3>Script Output:</h3><ul><li><p>For each log file, the script creates a PowerShell custom object containing:</p><ul><li><p><code>{#LOGFILE_NAME}</code>: The name of the log file (for Zabbix discovery).</p></li><li><p><code>original_path</code>: The full path to the log file.</p></li><li><p><code>status</code>: <code>1</code> if an error was found, <code>0</code> otherwise.</p></li><li><p><code>latest_error_message</code>: The first line of the latest non-ignored error message, if found.</p></li><li><p><code>latest_error_date</code>: The date of the <code>latest_error_message</code>.</p></li></ul></li><li><p>Finally, all these individual file results are compiled into a single JSON object under a "data" key and saved to the <code>JsonOutputFilePath</code>. This JSON file is what Zabbix would typically consume to update its monitoring dashboards and trigger alerts.</p></li></ul><h4>Zabbix configuration</h4><p>Edit Zabbix agent configuration file:<code>"C:\Program Files\Zabbix Agent\zabbix_agentd.conf" then restart Zabbix service.</code></p><pre><code># UserParameter for JSON file last modification time
UserParameter=file.mtime[*],powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "Get-Item '$1' | Select-Object -ExpandProperty LastWriteTimeUtc | ForEach-Object { [long][double]((Get-Date $_ -UFormat %s) + 0.5) }"


# UserParameter for Log Error Discovery (used by Zabbix LLD)
# This will now read the pre-generated JSON from the file
UserParameter=log.errors.discover,powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "Get-Content \"D:\ScriptsLogs\ZabbixLogErrors.json\""

# UserParameter for Log Error Status (per discovered log file)
# This reads from the file, converts JSON, filters, and gets the status.
UserParameter=log.errors.status[*],powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "((Get-Content 'D:\ScriptsLogs\ZabbixLogErrors.json' | ConvertFrom-Json).data | Where-Object {$_.'{#LOGFILE_NAME}' -eq \"$1\"}).status"

# UserParameter for Latest Log Error Message (per discovered log file)
# This reads from the file, converts JSON, filters, and gets the message.
UserParameter=log.errors.message[*],powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "((Get-Content 'D:\ScriptsLogs\ZabbixLogErrors.json' | ConvertFrom-Json).data | Where-Object {$_.'{#LOGFILE_NAME}' -eq \"$1\"}).latest_error_message"

# UserParameter for Latest Log Error Date (per discovered log file)
# This reads from the file, converts JSON, filters, and gets the date.
UserParameter=log.errors.date[*],powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "((Get-Content 'D:\ScriptsLogs\ZabbixLogErrors.json' | ConvertFrom-Json).data | Where-Object {$_.'{#LOGFILE_NAME}' -eq \"$1\"}).latest_error_date"
</code></pre><ul><li><p><code>UserParameter=file.mtime[*],powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "Get-Item '$1' | Select-Object -ExpandProperty LastWriteTimeUtc | ForEach-Object { [long][double]((Get-Date $_ -UFormat %s) + 0.5) }"</code></p><ul><li><p><strong>Purpose:</strong> This <code>UserParameter</code> is designed to monitor the last modification time (mtime) of any file specified as an argument (<code>$1</code>). It&#8217;s used to check how recently the <code>ZabbixLogErrors.json</code> file was updated by PowerShell script.</p></li><li><p><strong>Why it's needed:</strong> Zabbix can use this item to ensure that the log error monitoring script is running regularly and successfully generating its output file. If the file's modification time is too old, it could indicate that the script has failed or stopped running.</p></li></ul></li><li><p><code>UserParameter=log.errors.discover,powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "Get-Content \"D:\ScriptsLogs\ZabbixLogErrors.json\""</code></p><ul><li><p><strong>Purpose:</strong> This <code>UserParameter</code> is specifically for Zabbix's Low-Level Discovery (LLD) feature. It reads the entire content of the <code>ZabbixLogErrors.json</code> file, which contains the analysis results for all monitored log files.</p></li><li><p><strong>Why it's needed:</strong> Zabbix will consume this JSON output to automatically discover individual log files (using <code>{#LOGFILE_NAME}</code> as the discovery key) and then create specific monitoring items and triggers for each discovered log file (e.g., status, message, date). This avoids the need to manually configure each log file in Zabbix.</p></li></ul></li><li><p><code>UserParameter=log.errors.status[*],powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "((Get-Content 'D:\ScriptsLogs\ZabbixLogErrors.json' | ConvertFrom-Json).data | Where-Object {$_.'{#LOGFILE_NAME}' -eq \"$1\"}).status"</code></p><ul><li><p><strong>Purpose:</strong> This <code>UserParameter</code> retrieves the <code>status</code> (0 for no error, 1 for error) for a <em>specific</em> log file. The <code>[*]</code> indicates that it takes an argument, which will be the <code>{#LOGFILE_NAME}</code> discovered by the LLD rule.</p></li><li><p><strong>Why it's needed:</strong> This is the core metric for monitoring. Zabbix will use this item to know if a particular log file has reported an error. A trigger can be set up to alert when this status becomes <code>1</code>.</p></li></ul></li><li><p><code>UserParameter=log.errors.message[*],powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "((Get-Content 'D:\ScriptsLogs\ZabbixLogErrors.json' | ConvertFrom-Json).data | Where-Object {$_.'{#LOGFILE_NAME}' -eq \"$1\"}).latest_error_message"</code></p><ul><li><p><strong>Purpose:</strong> This <code>UserParameter</code> retrieves the <code>latest_error_message</code> for a specific log file.</p></li><li><p><strong>Why it's needed:</strong> When an error is detected, this item provides the actual error message, which is crucial for troubleshooting and understanding the nature of the problem directly from the Zabbix interface or in alert notifications.</p></li></ul></li><li><p><code>UserParameter=log.errors.date[*],powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "((Get-Content 'D:\ScriptsLogs\ZabbixLogErrors.json' | ConvertFrom-Json).data | Where-Object {$_.'{#LOGFILE_NAME}' -eq \"$1\"}).latest_error_date"</code></p><ul><li><p><strong>Purpose:</strong> This <code>UserParameter</code> retrieves the <code>latest_error_date</code> for a specific log file.</p></li><li><p><strong>Why it's needed:</strong> This provides the exact date when the latest error occurred in that specific log file, which is important for context and for quickly identifying if an error is recent or persistent.</p></li></ul></li></ul><h4>Creating Zabbix template</h4><p>We need to create Zabbix template,item and alert because it provides a structured and efficient way to apply a consistent set of monitoring configurations to one or more hosts. Instead of manually configuring each item, trigger, and discovery rule for every server that needs log error monitoring.The template would contain the <code>log.errors.discover</code> <code>UserParameter</code> as part of an LLD rule. This rule would automatically discover each log file reported in <code>ZabbixLogErrors.json</code> output and create individual monitoring items (like <code>log.errors.status</code>, <code>log.errors.message</code>, <code>log.errors.date</code>) for each discovered log file. Without a template using LLD, you'd have to manually define items for every single log file on every server.</p><p>Expand Data collection and click Templates-Create Template</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GJSL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd550571-bf8a-4757-a99e-e18450ba8a0e_252x738.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GJSL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd550571-bf8a-4757-a99e-e18450ba8a0e_252x738.png 424w, https://substackcdn.com/image/fetch/$s_!GJSL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd550571-bf8a-4757-a99e-e18450ba8a0e_252x738.png 848w, https://substackcdn.com/image/fetch/$s_!GJSL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd550571-bf8a-4757-a99e-e18450ba8a0e_252x738.png 1272w, https://substackcdn.com/image/fetch/$s_!GJSL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd550571-bf8a-4757-a99e-e18450ba8a0e_252x738.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GJSL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd550571-bf8a-4757-a99e-e18450ba8a0e_252x738.png" width="252" height="738" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bd550571-bf8a-4757-a99e-e18450ba8a0e_252x738.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:738,&quot;width&quot;:252,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:30976,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/166961305?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd550571-bf8a-4757-a99e-e18450ba8a0e_252x738.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!GJSL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd550571-bf8a-4757-a99e-e18450ba8a0e_252x738.png 424w, https://substackcdn.com/image/fetch/$s_!GJSL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd550571-bf8a-4757-a99e-e18450ba8a0e_252x738.png 848w, https://substackcdn.com/image/fetch/$s_!GJSL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd550571-bf8a-4757-a99e-e18450ba8a0e_252x738.png 1272w, https://substackcdn.com/image/fetch/$s_!GJSL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd550571-bf8a-4757-a99e-e18450ba8a0e_252x738.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>After template is created,select it and click Discovery.</p><p>In a Zabbix template, <strong>discovery</strong> (specifically referred to as Low-Level Discovery or LLD) is a powerful feature that allows Zabbix to automatically detect components on a host and then create corresponding monitoring items, triggers, and graphs for them.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5OiY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb220dac4-904e-4e9c-8b50-edecbf97b512_910x58.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5OiY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb220dac4-904e-4e9c-8b50-edecbf97b512_910x58.png 424w, https://substackcdn.com/image/fetch/$s_!5OiY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb220dac4-904e-4e9c-8b50-edecbf97b512_910x58.png 848w, https://substackcdn.com/image/fetch/$s_!5OiY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb220dac4-904e-4e9c-8b50-edecbf97b512_910x58.png 1272w, https://substackcdn.com/image/fetch/$s_!5OiY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb220dac4-904e-4e9c-8b50-edecbf97b512_910x58.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5OiY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb220dac4-904e-4e9c-8b50-edecbf97b512_910x58.png" width="910" height="58" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b220dac4-904e-4e9c-8b50-edecbf97b512_910x58.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:58,&quot;width&quot;:910,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:13656,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/166961305?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb220dac4-904e-4e9c-8b50-edecbf97b512_910x58.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5OiY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb220dac4-904e-4e9c-8b50-edecbf97b512_910x58.png 424w, https://substackcdn.com/image/fetch/$s_!5OiY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb220dac4-904e-4e9c-8b50-edecbf97b512_910x58.png 848w, https://substackcdn.com/image/fetch/$s_!5OiY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb220dac4-904e-4e9c-8b50-edecbf97b512_910x58.png 1272w, https://substackcdn.com/image/fetch/$s_!5OiY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb220dac4-904e-4e9c-8b50-edecbf97b512_910x58.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Populate is as below</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!iALY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd22f6a58-41f0-406b-b80d-5e4adab12cb9_1553x618.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!iALY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd22f6a58-41f0-406b-b80d-5e4adab12cb9_1553x618.png 424w, https://substackcdn.com/image/fetch/$s_!iALY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd22f6a58-41f0-406b-b80d-5e4adab12cb9_1553x618.png 848w, https://substackcdn.com/image/fetch/$s_!iALY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd22f6a58-41f0-406b-b80d-5e4adab12cb9_1553x618.png 1272w, https://substackcdn.com/image/fetch/$s_!iALY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd22f6a58-41f0-406b-b80d-5e4adab12cb9_1553x618.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!iALY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd22f6a58-41f0-406b-b80d-5e4adab12cb9_1553x618.png" width="1456" height="579" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d22f6a58-41f0-406b-b80d-5e4adab12cb9_1553x618.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:579,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:49637,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/166961305?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd22f6a58-41f0-406b-b80d-5e4adab12cb9_1553x618.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!iALY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd22f6a58-41f0-406b-b80d-5e4adab12cb9_1553x618.png 424w, https://substackcdn.com/image/fetch/$s_!iALY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd22f6a58-41f0-406b-b80d-5e4adab12cb9_1553x618.png 848w, https://substackcdn.com/image/fetch/$s_!iALY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd22f6a58-41f0-406b-b80d-5e4adab12cb9_1553x618.png 1272w, https://substackcdn.com/image/fetch/$s_!iALY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd22f6a58-41f0-406b-b80d-5e4adab12cb9_1553x618.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In Discovery rules,select rule and click on Item prototypes</p><p>In Zabbix, <strong>item prototypes</strong> are blueprints or templates for creating actual monitoring items automatically through Low-Level Discovery (LLD). Instead of defining each monitoring item manually for every discovered component (like a log file, a file system, or a network interface), you define an item prototype within an LLD rule.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!K7uK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7107554-de43-4d9a-9d04-84a852f86028_1603x100.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!K7uK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7107554-de43-4d9a-9d04-84a852f86028_1603x100.png 424w, https://substackcdn.com/image/fetch/$s_!K7uK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7107554-de43-4d9a-9d04-84a852f86028_1603x100.png 848w, https://substackcdn.com/image/fetch/$s_!K7uK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7107554-de43-4d9a-9d04-84a852f86028_1603x100.png 1272w, https://substackcdn.com/image/fetch/$s_!K7uK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7107554-de43-4d9a-9d04-84a852f86028_1603x100.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!K7uK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7107554-de43-4d9a-9d04-84a852f86028_1603x100.png" width="1456" height="91" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f7107554-de43-4d9a-9d04-84a852f86028_1603x100.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:91,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:33490,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/166961305?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7107554-de43-4d9a-9d04-84a852f86028_1603x100.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!K7uK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7107554-de43-4d9a-9d04-84a852f86028_1603x100.png 424w, https://substackcdn.com/image/fetch/$s_!K7uK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7107554-de43-4d9a-9d04-84a852f86028_1603x100.png 848w, https://substackcdn.com/image/fetch/$s_!K7uK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7107554-de43-4d9a-9d04-84a852f86028_1603x100.png 1272w, https://substackcdn.com/image/fetch/$s_!K7uK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff7107554-de43-4d9a-9d04-84a852f86028_1603x100.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Create 3 prototypes as below, one for each Value in PowerShell script:error message,error date and error status, change Update interval if needed.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oF86!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9c6ab7e-6d93-44d4-a5f2-bfc7a17e236d_1094x701.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oF86!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9c6ab7e-6d93-44d4-a5f2-bfc7a17e236d_1094x701.png 424w, https://substackcdn.com/image/fetch/$s_!oF86!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9c6ab7e-6d93-44d4-a5f2-bfc7a17e236d_1094x701.png 848w, https://substackcdn.com/image/fetch/$s_!oF86!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9c6ab7e-6d93-44d4-a5f2-bfc7a17e236d_1094x701.png 1272w, https://substackcdn.com/image/fetch/$s_!oF86!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9c6ab7e-6d93-44d4-a5f2-bfc7a17e236d_1094x701.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oF86!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9c6ab7e-6d93-44d4-a5f2-bfc7a17e236d_1094x701.png" width="1094" height="701" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d9c6ab7e-6d93-44d4-a5f2-bfc7a17e236d_1094x701.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:701,&quot;width&quot;:1094,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:60029,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/166961305?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9c6ab7e-6d93-44d4-a5f2-bfc7a17e236d_1094x701.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!oF86!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9c6ab7e-6d93-44d4-a5f2-bfc7a17e236d_1094x701.png 424w, https://substackcdn.com/image/fetch/$s_!oF86!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9c6ab7e-6d93-44d4-a5f2-bfc7a17e236d_1094x701.png 848w, https://substackcdn.com/image/fetch/$s_!oF86!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9c6ab7e-6d93-44d4-a5f2-bfc7a17e236d_1094x701.png 1272w, https://substackcdn.com/image/fetch/$s_!oF86!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9c6ab7e-6d93-44d4-a5f2-bfc7a17e236d_1094x701.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ipqd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44bd1cb7-9edc-4129-b8a6-2a9bd01d42ef_1044x746.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ipqd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44bd1cb7-9edc-4129-b8a6-2a9bd01d42ef_1044x746.png 424w, https://substackcdn.com/image/fetch/$s_!ipqd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44bd1cb7-9edc-4129-b8a6-2a9bd01d42ef_1044x746.png 848w, https://substackcdn.com/image/fetch/$s_!ipqd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44bd1cb7-9edc-4129-b8a6-2a9bd01d42ef_1044x746.png 1272w, https://substackcdn.com/image/fetch/$s_!ipqd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44bd1cb7-9edc-4129-b8a6-2a9bd01d42ef_1044x746.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ipqd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44bd1cb7-9edc-4129-b8a6-2a9bd01d42ef_1044x746.png" width="1044" height="746" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/44bd1cb7-9edc-4129-b8a6-2a9bd01d42ef_1044x746.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:746,&quot;width&quot;:1044,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:63766,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/166961305?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44bd1cb7-9edc-4129-b8a6-2a9bd01d42ef_1044x746.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ipqd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44bd1cb7-9edc-4129-b8a6-2a9bd01d42ef_1044x746.png 424w, https://substackcdn.com/image/fetch/$s_!ipqd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44bd1cb7-9edc-4129-b8a6-2a9bd01d42ef_1044x746.png 848w, https://substackcdn.com/image/fetch/$s_!ipqd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44bd1cb7-9edc-4129-b8a6-2a9bd01d42ef_1044x746.png 1272w, https://substackcdn.com/image/fetch/$s_!ipqd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F44bd1cb7-9edc-4129-b8a6-2a9bd01d42ef_1044x746.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GAkl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd05615bc-541f-4588-be9b-2a71ede8972e_1530x833.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GAkl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd05615bc-541f-4588-be9b-2a71ede8972e_1530x833.png 424w, https://substackcdn.com/image/fetch/$s_!GAkl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd05615bc-541f-4588-be9b-2a71ede8972e_1530x833.png 848w, https://substackcdn.com/image/fetch/$s_!GAkl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd05615bc-541f-4588-be9b-2a71ede8972e_1530x833.png 1272w, https://substackcdn.com/image/fetch/$s_!GAkl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd05615bc-541f-4588-be9b-2a71ede8972e_1530x833.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GAkl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd05615bc-541f-4588-be9b-2a71ede8972e_1530x833.png" width="1456" height="793" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d05615bc-541f-4588-be9b-2a71ede8972e_1530x833.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:793,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:81621,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/166961305?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd05615bc-541f-4588-be9b-2a71ede8972e_1530x833.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!GAkl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd05615bc-541f-4588-be9b-2a71ede8972e_1530x833.png 424w, https://substackcdn.com/image/fetch/$s_!GAkl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd05615bc-541f-4588-be9b-2a71ede8972e_1530x833.png 848w, https://substackcdn.com/image/fetch/$s_!GAkl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd05615bc-541f-4588-be9b-2a71ede8972e_1530x833.png 1272w, https://substackcdn.com/image/fetch/$s_!GAkl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd05615bc-541f-4588-be9b-2a71ede8972e_1530x833.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Now create a trigger prototype</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pZGJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecd0e2b9-3b43-4ab7-add0-1350de4bbb9a_1123x811.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pZGJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecd0e2b9-3b43-4ab7-add0-1350de4bbb9a_1123x811.png 424w, https://substackcdn.com/image/fetch/$s_!pZGJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecd0e2b9-3b43-4ab7-add0-1350de4bbb9a_1123x811.png 848w, https://substackcdn.com/image/fetch/$s_!pZGJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecd0e2b9-3b43-4ab7-add0-1350de4bbb9a_1123x811.png 1272w, https://substackcdn.com/image/fetch/$s_!pZGJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecd0e2b9-3b43-4ab7-add0-1350de4bbb9a_1123x811.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pZGJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecd0e2b9-3b43-4ab7-add0-1350de4bbb9a_1123x811.png" width="1123" height="811" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ecd0e2b9-3b43-4ab7-add0-1350de4bbb9a_1123x811.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:811,&quot;width&quot;:1123,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:68565,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/166961305?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecd0e2b9-3b43-4ab7-add0-1350de4bbb9a_1123x811.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pZGJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecd0e2b9-3b43-4ab7-add0-1350de4bbb9a_1123x811.png 424w, https://substackcdn.com/image/fetch/$s_!pZGJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecd0e2b9-3b43-4ab7-add0-1350de4bbb9a_1123x811.png 848w, https://substackcdn.com/image/fetch/$s_!pZGJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecd0e2b9-3b43-4ab7-add0-1350de4bbb9a_1123x811.png 1272w, https://substackcdn.com/image/fetch/$s_!pZGJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fecd0e2b9-3b43-4ab7-add0-1350de4bbb9a_1123x811.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><pre><code># expression to detect error
last(/Template Log Error Monitoring/log.errors.status["{#LOGFILE_NAME}"])=1
# expression to fix the error
last(/Template Log Error Monitoring/log.errors.status["{#LOGFILE_NAME}"])=0</code></pre><ul><li><p><code>last(...)</code>: This is a Zabbix trigger function. It returns the <strong>last (most recent) value</strong> collected for the specified item.</p></li><li><p><code>/Template Log Error Monitoring/</code>: This specifies the <strong>template</strong> that the item belongs to. In this case, it's a template likely named "Template Log Error Monitoring". This helps Zabbix locate the correct item even if multiple templates have similarly named items.</p></li><li><p><code>log.errors.status["{#LOGFILE_NAME}"]</code>: This refers to a specific <strong>item</strong> that Zabbix is monitoring.</p><ul><li><p><code>log.errors.status</code> is the item key, which corresponds to one of the <code>UserParameter</code> definitions you provided earlier: <code>UserParameter=log.errors.status[*],powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "((Get-Content 'D:\ScriptsLogs\ZabbixLogErrors.json' | ConvertFrom-Json).data | Where-Object {$_.'{#LOGFILE_NAME}' -eq \"$1\"}).status"</code>. This item retrieves the error status (0 or 1) for a specific log file.</p></li><li><p><code>["{#LOGFILE_NAME}"]</code> is where the <strong>Low-Level Discovery (LLD) macro</strong> comes into play. When Zabbix's LLD rule discovers a particular log file,it automatically creates actual items using this prototype. For instance, <code>{#LOGFILE_NAME}</code> would be replaced with <code>1.txt</code>, resulting in an actual item key like <code>log.errors.status["1.txt"]</code>.</p></li></ul></li><li><p><code>=1</code>: This is the <strong>condition</strong> for the trigger to fire. It means "if the last value collected by the <code>log.errors.status</code> item for this specific log file is equal to 1.",if 0,clear the error</p></li></ul><p><strong>In summary, the entire expression </strong><code>last(/Template Log Error Monitoring/log.errors.status["{#LOGFILE_NAME}"])=1</code><strong> means:</strong></p><p>"If the most recent status value reported for any discovered log file (as determined by the <code>log.errors.status</code> item in the 'Template Log Error Monitoring' template) is <code>1</code> (indicating an error), then activate this trigger.",otherwise,close it.</p><p>Now click on host where PowerShell script is running on, in templates section click Select and find the template we just created,now Template is linked to the host and Items and triggers will be created.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!stn1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833fdae4-ef57-4aea-8e45-8f42cc50f761_986x406.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!stn1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833fdae4-ef57-4aea-8e45-8f42cc50f761_986x406.png 424w, https://substackcdn.com/image/fetch/$s_!stn1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833fdae4-ef57-4aea-8e45-8f42cc50f761_986x406.png 848w, https://substackcdn.com/image/fetch/$s_!stn1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833fdae4-ef57-4aea-8e45-8f42cc50f761_986x406.png 1272w, https://substackcdn.com/image/fetch/$s_!stn1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833fdae4-ef57-4aea-8e45-8f42cc50f761_986x406.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!stn1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833fdae4-ef57-4aea-8e45-8f42cc50f761_986x406.png" width="986" height="406" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/833fdae4-ef57-4aea-8e45-8f42cc50f761_986x406.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:406,&quot;width&quot;:986,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:34109,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/166961305?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833fdae4-ef57-4aea-8e45-8f42cc50f761_986x406.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!stn1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833fdae4-ef57-4aea-8e45-8f42cc50f761_986x406.png 424w, https://substackcdn.com/image/fetch/$s_!stn1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833fdae4-ef57-4aea-8e45-8f42cc50f761_986x406.png 848w, https://substackcdn.com/image/fetch/$s_!stn1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833fdae4-ef57-4aea-8e45-8f42cc50f761_986x406.png 1272w, https://substackcdn.com/image/fetch/$s_!stn1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F833fdae4-ef57-4aea-8e45-8f42cc50f761_986x406.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h4>Creating Item for monitoring JSON file age</h4><p>We need to monitor JSON file modification date so we can verify that script for monitoring script file is working and that Zabbix receives updated information.</p><p>In UserParameters section in Zabbix agent config file we already implemented JSON file monitoring</p><pre><code><code># UserParameter for JSON file last modification time
UserParameter=file.mtime[*],powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "Get-Item '$1' | Select-Object -ExpandProperty LastWriteTimeUtc | ForEach-Object { [long][double]((Get-Date $_ -UFormat %s) + 0.5) }"</code></code></pre><p>On the same host we attached template to click in Items-Create New item</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!yrHB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e513bc-b6f4-4437-93f0-816c6b8d2765_647x65.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!yrHB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e513bc-b6f4-4437-93f0-816c6b8d2765_647x65.png 424w, https://substackcdn.com/image/fetch/$s_!yrHB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e513bc-b6f4-4437-93f0-816c6b8d2765_647x65.png 848w, https://substackcdn.com/image/fetch/$s_!yrHB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e513bc-b6f4-4437-93f0-816c6b8d2765_647x65.png 1272w, https://substackcdn.com/image/fetch/$s_!yrHB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e513bc-b6f4-4437-93f0-816c6b8d2765_647x65.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!yrHB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e513bc-b6f4-4437-93f0-816c6b8d2765_647x65.png" width="647" height="65" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e3e513bc-b6f4-4437-93f0-816c6b8d2765_647x65.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:65,&quot;width&quot;:647,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:8373,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/166961305?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e513bc-b6f4-4437-93f0-816c6b8d2765_647x65.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!yrHB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e513bc-b6f4-4437-93f0-816c6b8d2765_647x65.png 424w, https://substackcdn.com/image/fetch/$s_!yrHB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e513bc-b6f4-4437-93f0-816c6b8d2765_647x65.png 848w, https://substackcdn.com/image/fetch/$s_!yrHB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e513bc-b6f4-4437-93f0-816c6b8d2765_647x65.png 1272w, https://substackcdn.com/image/fetch/$s_!yrHB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3e513bc-b6f4-4437-93f0-816c6b8d2765_647x65.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kTTS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1be14d7-1098-487d-b110-f1a44353caad_1320x822.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kTTS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1be14d7-1098-487d-b110-f1a44353caad_1320x822.png 424w, https://substackcdn.com/image/fetch/$s_!kTTS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1be14d7-1098-487d-b110-f1a44353caad_1320x822.png 848w, https://substackcdn.com/image/fetch/$s_!kTTS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1be14d7-1098-487d-b110-f1a44353caad_1320x822.png 1272w, https://substackcdn.com/image/fetch/$s_!kTTS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1be14d7-1098-487d-b110-f1a44353caad_1320x822.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kTTS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1be14d7-1098-487d-b110-f1a44353caad_1320x822.png" width="1320" height="822" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f1be14d7-1098-487d-b110-f1a44353caad_1320x822.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:822,&quot;width&quot;:1320,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:86927,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/166961305?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1be14d7-1098-487d-b110-f1a44353caad_1320x822.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kTTS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1be14d7-1098-487d-b110-f1a44353caad_1320x822.png 424w, https://substackcdn.com/image/fetch/$s_!kTTS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1be14d7-1098-487d-b110-f1a44353caad_1320x822.png 848w, https://substackcdn.com/image/fetch/$s_!kTTS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1be14d7-1098-487d-b110-f1a44353caad_1320x822.png 1272w, https://substackcdn.com/image/fetch/$s_!kTTS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1be14d7-1098-487d-b110-f1a44353caad_1320x822.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This item has path to JSON file and it tells powershell script which file to monitor $1 is parameter, it this case it&#8217;s Item key.</p><pre><code><code>UserParameter=file.mtime[*],powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "Get-Item '$1</code></code></pre><h4>Creating trigger</h4><p>Now click Triggers-Create new trigger</p><pre><code># problem expression
nodata(/server.example.com/file.mtime[D:/ScriptsLogs/ZabbixLogErrors.json],3h)=1
# recovery expression
nodata(/server.example.com/file.mtime[D:/ScriptsLogs/ZabbixLogErrors.json],3h)=1</code></pre><p>If there are no new data in 3 hours,create alert.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!njv4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a24dac-7218-4a01-9d12-083498a516a3_1276x790.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!njv4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a24dac-7218-4a01-9d12-083498a516a3_1276x790.png 424w, https://substackcdn.com/image/fetch/$s_!njv4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a24dac-7218-4a01-9d12-083498a516a3_1276x790.png 848w, https://substackcdn.com/image/fetch/$s_!njv4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a24dac-7218-4a01-9d12-083498a516a3_1276x790.png 1272w, https://substackcdn.com/image/fetch/$s_!njv4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a24dac-7218-4a01-9d12-083498a516a3_1276x790.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!njv4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a24dac-7218-4a01-9d12-083498a516a3_1276x790.png" width="1276" height="790" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/91a24dac-7218-4a01-9d12-083498a516a3_1276x790.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:790,&quot;width&quot;:1276,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:84408,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/166961305?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a24dac-7218-4a01-9d12-083498a516a3_1276x790.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!njv4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a24dac-7218-4a01-9d12-083498a516a3_1276x790.png 424w, https://substackcdn.com/image/fetch/$s_!njv4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a24dac-7218-4a01-9d12-083498a516a3_1276x790.png 848w, https://substackcdn.com/image/fetch/$s_!njv4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a24dac-7218-4a01-9d12-083498a516a3_1276x790.png 1272w, https://substackcdn.com/image/fetch/$s_!njv4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91a24dac-7218-4a01-9d12-083498a516a3_1276x790.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/monitoring-log-files-with-powershell?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/monitoring-log-files-with-powershell?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/monitoring-log-files-with-powershell/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/monitoring-log-files-with-powershell/comments"><span>Leave a comment</span></a></p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading SysAdmin Journal! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[NPS logs forwarding to MS SQL server]]></title><description><![CDATA[Script published on MS Web site has some issues, so i modified it a bit.]]></description><link>https://adminjournal.substack.com/p/configuring-nps-logs-forwarding-to</link><guid isPermaLink="false">https://adminjournal.substack.com/p/configuring-nps-logs-forwarding-to</guid><dc:creator><![CDATA[Драган Вучановић]]></dc:creator><pubDate>Mon, 23 Jun 2025 08:05:05 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!-add!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec96601e-b943-49b9-8914-362dadfb78c0_1094x782.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-add!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec96601e-b943-49b9-8914-362dadfb78c0_1094x782.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-add!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec96601e-b943-49b9-8914-362dadfb78c0_1094x782.png 424w, https://substackcdn.com/image/fetch/$s_!-add!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec96601e-b943-49b9-8914-362dadfb78c0_1094x782.png 848w, https://substackcdn.com/image/fetch/$s_!-add!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec96601e-b943-49b9-8914-362dadfb78c0_1094x782.png 1272w, https://substackcdn.com/image/fetch/$s_!-add!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec96601e-b943-49b9-8914-362dadfb78c0_1094x782.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-add!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec96601e-b943-49b9-8914-362dadfb78c0_1094x782.png" width="1094" height="782" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ec96601e-b943-49b9-8914-362dadfb78c0_1094x782.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:782,&quot;width&quot;:1094,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:367612,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://adminjournal.substack.com/i/166578585?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec96601e-b943-49b9-8914-362dadfb78c0_1094x782.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-add!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec96601e-b943-49b9-8914-362dadfb78c0_1094x782.png 424w, https://substackcdn.com/image/fetch/$s_!-add!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec96601e-b943-49b9-8914-362dadfb78c0_1094x782.png 848w, https://substackcdn.com/image/fetch/$s_!-add!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec96601e-b943-49b9-8914-362dadfb78c0_1094x782.png 1272w, https://substackcdn.com/image/fetch/$s_!-add!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec96601e-b943-49b9-8914-362dadfb78c0_1094x782.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p></p><p>Script published on <a href="https://learn.microsoft.com/en-us/windows/win32/nps/sql-programmability">MS Web site</a> has some issues, so i modified it a bit.</p><p>This SQL script is designed to set up and configure a <strong>WifiMonitoring</strong> database in Microsoft SQL Server. It includes steps to:</p><div><hr></div><h2>1. Database Creation and Configuration</h2><ul><li><p><strong>Drop Existing Database:</strong> It first checks if a database named <code>WifiMonitoring</code> already exists. If it does, the script drops it to ensure a clean slate for the new database creation. This is useful for development or redeployment scenarios.</p></li><li><p><strong>Create Database:</strong> It then creates the <code>WifiMonitoring</code> database with specific file paths for its data (<code>.MDF</code>) and log (<code>.LDF</code>) files. It sets initial sizes and defines how the files should grow (10% increments). The database uses the <code>SQL_Latin1_General_CP1_CI_AS</code> collation, which defines rules for sorting and comparing character data.</p></li><li><p><strong>Alter Database Settings:</strong> A series of <code>ALTER DATABASE</code> commands follow to configure various settings for the <code>WifiMonitoring</code> database:</p><ul><li><p><code>AUTO_CLOSE OFF</code>: Prevents the database from automatically shutting down after the last user disconnects. This keeps it online for faster access.</p></li><li><p><code>TORN_PAGE_DETECTION ON</code>: Helps detect incomplete I/O operations that can lead to data corruption.</p></li><li><p><code>READ_WRITE</code>: Sets the database to be in read/write mode, allowing data modifications.</p></li><li><p><code>AUTO_SHRINK OFF</code>: Prevents the database from automatically shrinking its files, which can cause performance issues due to fragmentation.</p></li><li><p><code>ANSI_NULL_DEFAULT OFF</code>, <code>ANSI_NULLS OFF</code>, <code>CONCAT_NULL_YIELDS_NULL OFF</code>, <code>QUOTED_IDENTIFIER OFF</code>, <code>ANSI_WARNINGS OFF</code>: These settings control various ANSI standard behaviors related to null values, string concatenation, and identifier quoting. Setting them to <code>OFF</code> often indicates compatibility with older SQL Server versions or specific application requirements.</p></li><li><p><code>RECURSIVE_TRIGGERS OFF</code>: Disables triggers from firing recursively.</p></li><li><p><code>CURSOR_CLOSE_ON_COMMIT OFF</code> and <code>CURSOR_DEFAULT LOCAL</code>: Control the behavior of cursors.</p></li><li><p><code>AUTO_CREATE_STATISTICS ON</code> and <code>AUTO_UPDATE_STATISTICS ON</code>: Enable automatic creation and updating of statistics, which the query optimizer uses to create efficient execution plans.</p></li><li><p><code>DB_CHAINING OFF</code>: This conditional statement checks the SQL Server version and, if it matches certain older versions (SQL Server 2000 or 7.0), disables cross-database ownership chaining. This is a security-related setting.</p></li></ul></li></ul><div><hr></div><h2>2. Database Object Preparation</h2><ul><li><p><strong>Switch Context:</strong> <code>use [WifiMonitoring]</code> ensures that subsequent commands are executed within the newly created <code>WifiMonitoring</code> database.</p></li><li><p><strong>Drop Existing Objects:</strong> Similar to the database drop, the script checks for and drops existing stored procedures (<code>report_event</code>), tables (<code>accounting_data</code>), and user-defined data types (<code>ipaddress</code>) to ensure a clean deployment.</p></li><li><p><strong>Create Custom Data Type:</strong> <code>EXEC sp_addtype N'ipaddress', N'nvarchar (15)', N'not null'</code> creates a custom data type named <code>ipaddress</code> based on <code>nvarchar(15)</code>. This is likely to enforce a consistent format for storing IP addresses.</p></li></ul><div><hr></div><h2>3. Table Creation</h2><ul><li><p><strong>Create </strong><code>accounting_data</code><strong> Table:</strong> This is the core table for storing Wi-Fi monitoring data. It includes columns such as:</p><ul><li><p><code>id</code> (int, IDENTITY): A unique identifier for each record, auto-incrementing.</p></li><li><p><code>timestamp</code> (datetime): The time of the event.</p></li><li><p><code>Computer_Name</code> (nvarchar): The name of the computer involved.</p></li><li><p><code>Packet_Type</code> (int): The type of network packet.</p></li><li><p><code>User_Name</code>, <code>F_Q_User_Name</code>, <code>SAM_Account_Name</code>: Various user-related identifiers.</p></li><li><p><code>Called_Station_Id</code>, <code>Calling_Station_Id</code>: Identifiers for the called and calling stations (e.g., MAC addresses).</p></li><li><p><code>NAS_Identifier</code>, <code>NAS_IP_Address</code>: Information about the Network Access Server.</p></li><li><p><code>Client_IP_Address</code>, <code>Client_Friendly_Name</code>: Information about the client.</p></li><li><p><code>Reason_Code</code>, <code>Connect_Info</code>, <code>Service_Type</code>, <code>Authentication_Type</code>: Details about the connection and authentication.</p></li><li><p><code>NP_Policy_Name</code>, <code>Proxy_Policy_Name</code>: Policy names.</p></li><li><p><code>Provider_Type</code> column is most likely intended to store information about the <strong>source or type of the Wi-Fi.</strong></p></li></ul></li><li><p>A <code>PRIMARY KEY</code> constraint named <code>PK_accounting_data</code> is defined on the <code>id</code> column, ensuring data integrity and fast lookups.</p></li></ul><div><hr></div><h2>4. Stored Procedure Creation</h2><ul><li><p><strong>Create </strong><code>dbo.report_event</code><strong> Stored Procedure:</strong> This procedure is designed to insert data into the <code>accounting_data</code> table.</p><ul><li><p>It takes an XML document (<code>@doc NVARCHAR(MAX)</code>) as input, which is expected to contain event details.</p></li><li><p><code>sp_xml_preparedocument</code>: Parses the input XML into an in-memory representation, allowing it to be queried.</p></li><li><p><code>INSERT INTO ... SELECT ... FROM OPENXML</code>: This is the core of the data insertion. It uses <code>OPENXML</code> to extract data from the prepared XML document and insert it into the corresponding columns of the <code>accounting_data</code> table. The <code>WITH</code> clause maps XML elements/attributes to table columns.</p></li><li><p><code>sp_xml_removedocument</code>: Cleans up the in-memory XML document.</p></li><li><p><strong>Error Handling and Auditing:</strong> The procedure includes a <code>TRY...CATCH</code> block for robust error handling:</p><ul><li><p>If the data insertion is successful, it logs a success entry into a <code>dbo.report_event_audit</code> table (which is not defined in this script but is expected to exist). This audit includes information like host name, login name, and input length.</p></li><li><p>If an error occurs, it captures detailed error information (number, severity, state, line, procedure, message), logs it to the <code>dbo.report_event_audit</code> table (including the full XML input), and then re-raises the error to the caller, allowing the calling application to know about the failure.</p></li></ul></li></ul></li></ul><pre><code>IF EXISTS (SELECT name FROM master.dbo.sysdatabases WHERE name = N'WifiMonitoring')
    DROP DATABASE [WifiMonitoring]
GO

CREATE DATABASE [WifiMonitoring]  ON (NAME = N'WifiMonitoring_Data', 
                               FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL\data\WifiMonitoring_Data.MDF' , 
                               SIZE = 1, FILEGROWTH = 10%) 
                       LOG ON (NAME = N'WifiMonitoring_Log', 
                               FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL\data\WifiMonitoring_Log.LDF' , 
                               SIZE = 1, FILEGROWTH = 10%)
 COLLATE SQL_Latin1_General_CP1_CI_AS
GO

ALTER DATABASE [WifiMonitoring]
SET AUTO_CLOSE OFF
GO

ALTER DATABASE [WifiMonitoring]
SET TORN_PAGE_DETECTION ON
GO

ALTER DATABASE [WifiMonitoring]
SET READ_WRITE
GO

ALTER DATABASE [WifiMonitoring]
SET AUTO_SHRINK OFF
GO

ALTER DATABASE [WifiMonitoring]
SET ANSI_NULL_DEFAULT OFF
GO

ALTER DATABASE [WifiMonitoring]
SET RECURSIVE_TRIGGERS OFF
GO

ALTER DATABASE [WifiMonitoring]
SET ANSI_NULLS OFF
GO

ALTER DATABASE [WifiMonitoring]
SET CONCAT_NULL_YIELDS_NULL OFF
GO

ALTER DATABASE [WifiMonitoring]
SET CURSOR_CLOSE_ON_COMMIT OFF
GO

ALTER DATABASE [WifiMonitoring]
SET CURSOR_DEFAULT LOCAL
GO

ALTER DATABASE [WifiMonitoring]
SET QUOTED_IDENTIFIER OFF
GO

ALTER DATABASE [WifiMonitoring]
SET ANSI_WARNINGS OFF
GO

ALTER DATABASE [WifiMonitoring]
SET AUTO_CREATE_STATISTICS ON
GO

ALTER DATABASE [WifiMonitoring]
SET AUTO_UPDATE_STATISTICS ON
GO

if( ( (@@microsoftversion / power(2, 24) = 8) and (@@microsoftversion &amp; 0xffff &gt;= 724) ) or 
    ( (@@microsoftversion / power(2, 24) = 7) and (@@microsoftversion &amp; 0xffff &gt;= 1082) ) )
    ALTER DATABASE [WifiMonitoring] SET DB_CHAINING OFF
GO

use [WifiMonitoring]
GO

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[report_event]') and 
                                              OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[report_event]
GO

if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[accounting_data]') and 
                                              OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[accounting_data]
GO

if exists (select * from dbo.systypes where name = N'ipaddress')
exec sp_droptype N'ipaddress'
GO

EXEC sp_addtype N'ipaddress', N'nvarchar (15)', N'not null'
GO

IF OBJECT_ID('dbo.accounting_data', 'U') IS NOT NULL
BEGIN
    DROP TABLE [dbo].[accounting_data];
    PRINT 'Dropped existing dbo.accounting_data table.';
END
GO

PRINT 'Creating new dbo.accounting_data table with selected columns...';
CREATE TABLE [dbo].[accounting_data](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [Provider_Type] [NVARCHAR(50)] NULL,
    [timestamp] [datetime] NOT NULL,
    [Computer_Name] [nvarchar](255) NOT NULL,
    [Packet_Type] [int] NOT NULL,
    [User_Name] [nvarchar](255) NULL,
    [F_Q_User_Name] [nvarchar](255) NULL,
    [Called_Station_Id] [nvarchar](255) NULL,
    [Calling_Station_Id] [nvarchar](255) NULL,
    [NAS_Identifier] [nvarchar](255) NULL,
    [NAS_IP_Address] [ipaddress] NULL,
    [Client_IP_Address] [ipaddress] NULL,
    [Client_Friendly_Name] [nvarchar](255) NULL,
    [Reason_Code] [int] NULL, 
    [Connect_Info] [nvarchar](255) NULL,
    [Service_Type] [int] NULL,
    [Authentication_Type] [int] NULL,
    [NP_Policy_Name] [nvarchar](255) NULL,
    [Proxy_Policy_Name] [nvarchar](255) NULL,
    [SAM_Account_Name] [nvarchar](255) NULL,
CONSTRAINT [PK_accounting_data] PRIMARY KEY CLUSTERED
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY];
GO
PRINT 'New dbo.accounting_data table created successfully.';
GO


Create PROCEDURE dbo.report_event
    @doc NVARCHAR(MAX)
AS

SET NOCOUNT ON;

DECLARE @idoc INT;
DECLARE @record_timestamp DATETIME = GETUTCDATE();

BEGIN TRY
    -- Prepare XML document
    -- This creates an in-memory representation of the XML document.
    EXEC sp_xml_preparedocument @idoc OUTPUT, @doc;

    INSERT INTO dbo.accounting_data (
        [timestamp],
        Computer_Name,
        Provider_Type,
        Packet_Type,
        [User_Name],
        F_Q_User_Name,
        Called_Station_Id,
        Calling_Station_Id,
        NAS_Identifier,
        NAS_IP_Address,
        Client_IP_Address,
        Client_Friendly_Name,
        Reason_Code,
        Connect_Info,
        Service_Type,
        Authentication_Type,
        NP_Policy_Name,
        Proxy_Policy_Name,
        SAM_Account_Name
    )
    SELECT
        @record_timestamp,
        Computer_Name,
        Packet_Type,
        [User_Name],
        Fully_Qualifed_User_Name,
        Called_Station_Id,
        Calling_Station_Id,
        NAS_Identifier,
        NAS_IP_Address,
        Client_IP_Address,
        Client_Friendly_Name,
        Reason_Code,
        Connect_Info,
        Service_Type,
        Authentication_Type,
        NP_Policy_Name,
        Proxy_Policy_Name,
        SAM_Account_Name
    FROM OPENXML(@idoc, '/Event')
    WITH (
        Computer_Name NVARCHAR(255) './Computer-Name',
        Packet_Type INT './Packet-Type', 
        [User_Name] NVARCHAR(255) './User-Name',
        Fully_Qualifed_User_Name NVARCHAR(255) './Fully-Qualifed-User-Name',
        Called_Station_Id NVARCHAR(255) './Called-Station-Id',
        Calling_Station_Id NVARCHAR(255) './Calling-Station-Id',
        NAS_Identifier NVARCHAR(255) './NAS-Identifier',
        NAS_IP_Address dbo.ipaddress './NAS-IP-Address',
        Client_IP_Address dbo.ipaddress './Client-IP-Address',
        Client_Friendly_Name NVARCHAR(255) './Client-Friendly-Name',
        Reason_Code INT './Reason-Code', 
        Provider_Type NVARCHAR(50) './Provider_Type',
        Connect_Info NVARCHAR(255) './Connect-Info',
        Service_Type INT './Service-Type', 
        Authentication_Type INT './Authentication-Type', 
        NP_Policy_Name NVARCHAR(255) './NP-Policy-Name',
        Proxy_Policy_Name NVARCHAR(255) './Proxy-Policy-Name',
        SAM_Account_Name NVARCHAR(255) './SAM-Account-Name'
    );

    -- Clean up XML document from memory
    EXEC sp_xml_removedocument @idoc;

    -- Log successful execution
    INSERT INTO dbo.report_event_audit (success, host_name, login_name, input_length)
    VALUES (1, HOST_NAME(), SYSTEM_USER, DATALENGTH(@doc));

END TRY
BEGIN CATCH
    -- Clean up XML document in case of error
    IF @idoc IS NOT NULL
    BEGIN
        EXEC sp_xml_removedocument @idoc;
    END

    -- Capture richer error details
    DECLARE @error_number INT = ERROR_NUMBER();
    DECLARE @error_severity INT = ERROR_SEVERITY();
    DECLARE @error_state INT = ERROR_STATE();
    DECLARE @error_line INT = ERROR_LINE();
    DECLARE @error_procedure NVARCHAR(200) = ERROR_PROCEDURE();
    DECLARE @error_message NVARCHAR(MAX) = ERROR_MESSAGE();

    -- Create a more detailed error message for logging and raising
    DECLARE @detailed_error_msg NVARCHAR(MAX) =
        N'Error ' + CAST(@error_number AS NVARCHAR(20)) +
        N', Level ' + CAST(@error_severity AS NVARCHAR(20)) +
        N', State ' + CAST(@error_state AS NVARCHAR(20)) +
        N', Procedure ' + @error_procedure +
        N', Line ' + CAST(@error_line AS NVARCHAR(20)) +
        N': ' + @error_message;

    -- Log the new, detailed error information, including the full XML input
    INSERT INTO dbo.report_event_audit (
        success,
        error_message,
        error_line,
        host_name,
        login_name,
        input_length,
        xml_input
    )
    VALUES (
        0,
        @detailed_error_msg,
        @error_line,
        HOST_NAME(),
        SYSTEM_USER,
        DATALENGTH(@doc),
        @doc
    );

    -- Re-raise the detailed error to the caller, so the calling application knows the operation failed.
    RAISERROR(@detailed_error_msg, 16, 1);

END CATCH;
GO
PRINT 'dbo.report_event stored procedure altered successfully.';
GO</code></pre><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/configuring-nps-logs-forwarding-to?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/configuring-nps-logs-forwarding-to?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://adminjournal.substack.com/p/configuring-nps-logs-forwarding-to/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://adminjournal.substack.com/p/configuring-nps-logs-forwarding-to/comments"><span>Leave a comment</span></a></p><p></p>]]></content:encoded></item></channel></rss>