<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ivan Tsanev</title>
    <description>The latest articles on DEV Community by Ivan Tsanev (@ivantsanev13).</description>
    <link>https://dev.to/ivantsanev13</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3863634%2F13b893da-a2d4-44f8-ab7d-09124371c3e1.jpeg</url>
      <title>DEV Community: Ivan Tsanev</title>
      <link>https://dev.to/ivantsanev13</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ivantsanev13"/>
    <language>en</language>
    <item>
      <title>[Boost]</title>
      <dc:creator>Ivan Tsanev</dc:creator>
      <pubDate>Fri, 10 Apr 2026 23:06:14 +0000</pubDate>
      <link>https://dev.to/ivantsanev13/-1coe</link>
      <guid>https://dev.to/ivantsanev13/-1coe</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/ivantsanev13/running-vault-in-kubernetes-lessons-from-a-homelab-9m2" class="crayons-story__hidden-navigation-link"&gt;Running Vault in Kubernetes - Lessons from a Homelab&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/ivantsanev13" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3863634%2F13b893da-a2d4-44f8-ab7d-09124371c3e1.jpeg" alt="ivantsanev13 profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/ivantsanev13" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Ivan Tsanev
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Ivan Tsanev
                
              
              &lt;div id="story-author-preview-content-3460128" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/ivantsanev13" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3863634%2F13b893da-a2d4-44f8-ab7d-09124371c3e1.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Ivan Tsanev&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/ivantsanev13/running-vault-in-kubernetes-lessons-from-a-homelab-9m2" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 6&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/ivantsanev13/running-vault-in-kubernetes-lessons-from-a-homelab-9m2" id="article-link-3460128"&gt;
          Running Vault in Kubernetes - Lessons from a Homelab
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/kubernetes"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;kubernetes&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/vault"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;vault&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devops"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devops&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/security"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;security&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/ivantsanev13/running-vault-in-kubernetes-lessons-from-a-homelab-9m2#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            6 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>(not yet) Falco AI Agent - Part 1: Real-time Kubernetes Security Analysis with Claude🔍</title>
      <dc:creator>Ivan Tsanev</dc:creator>
      <pubDate>Fri, 10 Apr 2026 23:00:48 +0000</pubDate>
      <link>https://dev.to/ivantsanev13/not-yet-falco-ai-agent-part-1-real-time-kubernetes-security-analysis-with-claude-2pom</link>
      <guid>https://dev.to/ivantsanev13/not-yet-falco-ai-agent-part-1-real-time-kubernetes-security-analysis-with-claude-2pom</guid>
      <description>&lt;p&gt;Been running Falco on my bare metal Kubernetes cluster for a while. It sits on every node watching kernel syscalls, catching everything happening inside containers. Shell spawns, unexpected API connections, processes doing things they probably shouldn't. Sounds great until you're drowning in alerts at midnight and 90% of them are just sidecars doing their job.&lt;/p&gt;

&lt;p&gt;Every Falco alert now goes straight to Claude with full context - process names, syscall types, container, namespace, MITRE ATT&amp;amp;CK tag, all of it. Claude comes back with three things: what actually happened, whether it's a real threat or expected behavior, and what to do about it. No noise, no cryptic log lines, just a straight answer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh1u1a4gp37y33oqhluu4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh1u1a4gp37y33oqhluu4.png" alt="alert with Claude analysis" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And it gets it right. Grafana sidecar hitting the K8s API? "Expected behavior, allowlist it." Shell spawned inside the Vault container? "Worth investigating, verify this was authorized." It reads the context and gives you something actionable.&lt;/p&gt;

&lt;p&gt;The whole thing runs on bare metal K8s - Claude API key stored in HashiCorp Vault, synced by External Secrets Operator, deployed via ArgoCD. The dashboard was built 99% (I just picked the colours) by Claude Cowork at 1:18am.. 😄&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpshg9924ec6uujnomhzm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpshg9924ec6uujnomhzm.png" alt="dashboard overview" width="800" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is Part 1. It watches, analyzes, recommends.&lt;/p&gt;

&lt;p&gt;Part 2 is where the "not yet" part disappears - it stops analysing and starts acting. I just review and approve.&lt;/p&gt;

&lt;p&gt;Right now it tells me what to do. Next time it does it. 🚀&lt;/p&gt;

&lt;p&gt;If you're doing something similar or just want to chat about it, find me on LinkedIn, I am always up for a conversation :) &lt;/p&gt;

</description>
      <category>falco</category>
      <category>kubernetes</category>
      <category>claude</category>
      <category>security</category>
    </item>
    <item>
      <title>Running Vault in Kubernetes - Lessons from a Homelab</title>
      <dc:creator>Ivan Tsanev</dc:creator>
      <pubDate>Mon, 06 Apr 2026 10:13:28 +0000</pubDate>
      <link>https://dev.to/ivantsanev13/running-vault-in-kubernetes-lessons-from-a-homelab-9m2</link>
      <guid>https://dev.to/ivantsanev13/running-vault-in-kubernetes-lessons-from-a-homelab-9m2</guid>
      <description>&lt;p&gt;This post is aimed at engineers running Vault on bare metal or self-hosted Kubernetes — managed cloud clusters handle some of this automatically, but on-prem you're on your own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Vault in Kubernetes — Lessons from a Homelab
&lt;/h2&gt;

&lt;p&gt;Most Vault + Kubernetes tutorials cover the basics: install Vault, store a secret, inject it into a pod. This post covers what comes after that — persistent storage, unsealing, and getting secrets into pods properly using External Secrets Operator.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Vault in the First Place
&lt;/h2&gt;

&lt;p&gt;Kubernetes Secrets are not secret. They're base64 encoded — which is encoding, not encryption. Anyone with the right RBAC permissions can decode them in seconds. There's no audit trail, no rotation, no central management.&lt;/p&gt;

&lt;p&gt;Vault solves all of this. Secrets are encrypted at rest, every access is logged, and you can rotate credentials without touching your cluster.&lt;/p&gt;

&lt;p&gt;The problem is getting there.&lt;/p&gt;




&lt;h2&gt;
  
  
  Start with Persistent Storage
&lt;/h2&gt;

&lt;p&gt;The natural starting point is dev mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;dev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;devRootToken&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;root"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dev mode is convenient — Vault starts pre-initialized and pre-unsealed. Good for experimenting.&lt;/p&gt;

&lt;p&gt;I started there too. Then a network routing issue caused my cluster to restart. I was troubleshooting Tailscale subnet routing — trying to reach cluster services from outside my home network — which left the routing table in a broken state and eventually took down the whole cluster. After bringing everything back up, ESO couldn't sync anything. The secrets were gone because dev mode stores everything in memory.&lt;/p&gt;

&lt;p&gt;That's when persistent storage became obvious. Vault is deployed via the official HashiCorp Helm chart. Use a proper storage class from the start — the following are the relevant Helm values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;dev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="na"&gt;dataStorage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1Gi&lt;/span&gt;
    &lt;span class="na"&gt;storageClass&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;longhorn&lt;/span&gt;   &lt;span class="c1"&gt;# replace with your storage class&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One thing to know: switching from dev mode to production mode isn't a config swap. Dev mode doesn't create a PVC, but you do need to delete the existing StatefulSet first — otherwise Helm will try to update it in place and hit an immutable fields error. Delete it, redeploy with the new config, then initialize fresh with &lt;code&gt;vault operator init&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Unseal Problem
&lt;/h2&gt;

&lt;p&gt;Production Vault starts sealed after every restart. This is a security feature — if someone steals your disk, the data is useless without the unseal keys. But it also means every time your pod restarts, someone has to manually unseal it.&lt;/p&gt;

&lt;p&gt;The proper solution is auto-unseal via a cloud KMS (AWS KMS, Azure Key Vault, etc.). For a homelab, I built a simpler workaround — a Kubernetes CronJob that runs every minute and unseals Vault automatically.&lt;/p&gt;

&lt;p&gt;First, store your unseal keys in a K8s Secret. When you initialize Vault with &lt;code&gt;vault operator init&lt;/code&gt;, it generates 5 unseal keys and requires any 3 of them to unseal. Store 3 of those keys here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create secret generic vault-unseal-keys &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;key1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;UNSEAL_KEY_1&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;key2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;UNSEAL_KEY_2&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;key3&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;UNSEAL_KEY_3&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; vault
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then deploy the CronJob. It runs every minute, reads the keys from that Secret as environment variables, and passes them to &lt;code&gt;vault operator unseal&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;batch/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;CronJob&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vault-unsealer&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vault&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
  &lt;span class="na"&gt;jobTemplate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vault-unsealer&lt;/span&gt;
            &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/vault:1.18.1&lt;/span&gt;
            &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/bin/sh&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;-c&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
              &lt;span class="s"&gt;export VAULT_ADDR=http://vault.vault.svc:8200  # &amp;lt;service-name&amp;gt;.&amp;lt;namespace&amp;gt;.svc&lt;/span&gt;
              &lt;span class="s"&gt;vault operator unseal $KEY1&lt;/span&gt;
              &lt;span class="s"&gt;vault operator unseal $KEY2&lt;/span&gt;
              &lt;span class="s"&gt;vault operator unseal $KEY3&lt;/span&gt;
            &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;KEY1&lt;/span&gt;
              &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;secretKeyRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vault-unseal-keys&lt;/span&gt;  &lt;span class="c1"&gt;# the Secret we created above&lt;/span&gt;
                  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;key1&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;KEY2&lt;/span&gt;
              &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;secretKeyRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vault-unseal-keys&lt;/span&gt;
                  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;key2&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;KEY3&lt;/span&gt;
              &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;secretKeyRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vault-unseal-keys&lt;/span&gt;
                  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;key3&lt;/span&gt;
          &lt;span class="na"&gt;restartPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;OnFailure&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Worth noting: storing unseal keys in the same cluster as Vault is circular from a security standpoint — if someone compromises the cluster, they have both. For a homelab it's an acceptable trade-off. In production, use cloud KMS where the unseal key lives outside the cluster entirely.&lt;/p&gt;




&lt;h2&gt;
  
  
  External Secrets Operator
&lt;/h2&gt;

&lt;p&gt;Vault stores your secrets. But your pods need Kubernetes Secrets. These are two different things and Vault alone doesn't bridge the gap.&lt;/p&gt;

&lt;p&gt;That's what External Secrets Operator (ESO) does. It watches for &lt;code&gt;ExternalSecret&lt;/code&gt; resources in your cluster and automatically syncs secrets from Vault into native K8s Secrets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Vault (source of truth)
  → ESO watches ExternalSecret resources
  → Creates/updates K8s Secrets automatically
  → Pod consumes K8s Secret as env var or volume mount
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 1 — Tell ESO how to connect to Vault&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;ClusterSecretStore&lt;/code&gt; is a cluster-wide resource that defines the connection to your secret backend — in this case Vault. Think of it as a named connection configuration that all your namespaces can reference.&lt;/p&gt;

&lt;p&gt;ESO needs a token to authenticate against Vault. You store that token in a regular K8s Secret first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create secret generic vault-auth-token &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;YOUR_VAULT_TOKEN&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-n&lt;/span&gt; default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then reference it in the &lt;code&gt;ClusterSecretStore&lt;/code&gt;. The &lt;code&gt;tokenSecretRef&lt;/code&gt; block points to that K8s Secret — &lt;code&gt;name&lt;/code&gt; is the name of the secret, and &lt;code&gt;key&lt;/code&gt; is the field inside it that holds the actual Vault token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;external-secrets.io/v1beta1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterSecretStore&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vault-connection&lt;/span&gt;       &lt;span class="c1"&gt;# referenced by ExternalSecrets later&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;vault&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://vault.vault.svc:8200"&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;secret"&lt;/span&gt;           &lt;span class="c1"&gt;# the KV engine mount name in Vault&lt;/span&gt;
      &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;v2"&lt;/span&gt;
      &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;tokenSecretRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vault-auth-token&lt;/span&gt;   &lt;span class="c1"&gt;# K8s Secret that holds the Vault token&lt;/span&gt;
          &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;token&lt;/span&gt;               &lt;span class="c1"&gt;# the field inside that Secret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2 — Store the secret in Vault&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before ESO can sync anything, the secret needs to exist in Vault. If the path doesn't exist yet, ESO will report a &lt;code&gt;SecretSyncedError&lt;/code&gt; status on the ExternalSecret resource — easy to miss if you're not watching. Create the secret first (make sure &lt;code&gt;VAULT_ADDR&lt;/code&gt; and &lt;code&gt;VAULT_TOKEN&lt;/code&gt; are set in your shell):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;VAULT_ADDR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://&amp;lt;vault-address&amp;gt;:8200
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;VAULT_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your-vault-token&amp;gt;
vault kv put secret/myproject/production/database &lt;span class="nv"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"your-db-password"&lt;/span&gt;
&lt;span class="c"&gt;# "secret" here is the KV engine mount name, not a literal — adjust if yours is named differently&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3 — Define what to sync&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An &lt;code&gt;ExternalSecret&lt;/code&gt; tells ESO: fetch this specific secret from Vault and create a K8s Secret from it. It references the &lt;code&gt;ClusterSecretStore&lt;/code&gt; you defined above.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;remoteRef.key&lt;/code&gt; is the path to the secret in Vault. A common convention is to organize secrets by project and environment — &lt;code&gt;myproject/production/database&lt;/code&gt;, &lt;code&gt;myproject/staging/database&lt;/code&gt; — so different clusters or namespaces can point to the right environment just by changing the path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;external-secrets.io/v1beta1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ExternalSecret&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;database-credentials&lt;/span&gt;        &lt;span class="c1"&gt;# name of this ExternalSecret resource&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;refreshInterval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1h&lt;/span&gt;               &lt;span class="c1"&gt;# how often ESO re-syncs from Vault&lt;/span&gt;
  &lt;span class="na"&gt;secretStoreRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vault-connection&lt;/span&gt;          &lt;span class="c1"&gt;# references the ClusterSecretStore above&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ClusterSecretStore&lt;/span&gt;
  &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;database-credentials&lt;/span&gt;      &lt;span class="c1"&gt;# name of the K8s Secret ESO will create&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;secretKey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;db-password&lt;/span&gt;        &lt;span class="c1"&gt;# key name in the resulting K8s Secret&lt;/span&gt;
      &lt;span class="na"&gt;remoteRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myproject/production/database&lt;/span&gt;
        &lt;span class="na"&gt;property&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;password&lt;/span&gt;                   &lt;span class="c1"&gt;# the field inside that Vault secret&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ESO creates a K8s Secret called &lt;code&gt;database-credentials&lt;/code&gt; in the &lt;code&gt;production&lt;/code&gt; namespace and keeps it in sync. Update the value in Vault, the K8s Secret updates automatically within the refresh interval — without touching the cluster.&lt;/p&gt;




&lt;h2&gt;
  
  
  Env Vars vs Volume Mounts
&lt;/h2&gt;

&lt;p&gt;Once the K8s Secret exists, you have two ways to consume it in a pod.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Environment variables&lt;/strong&gt; are set at container start time and never update. If the secret rotates, the pod needs a restart to see the new value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Volume mounts&lt;/strong&gt; update automatically. When the K8s Secret changes, the mounted file updates inside the pod within roughly 60-90 seconds (kubelet sync period). No restart needed — as long as the app re-reads the file each time it needs the value rather than caching it at startup.&lt;/p&gt;

&lt;p&gt;Here's what it looks like in a full Deployment spec:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app:latest&lt;/span&gt;
          &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;credentials-vol&lt;/span&gt;
              &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/etc/secrets&lt;/span&gt;    &lt;span class="c1"&gt;# files appear here inside the container&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;credentials-vol&lt;/span&gt;
          &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;database-credentials&lt;/span&gt;   &lt;span class="c1"&gt;# the K8s Secret ESO created&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file name inside the pod matches the &lt;code&gt;secretKey&lt;/code&gt; field defined in the ExternalSecret — in this example &lt;code&gt;db-password&lt;/code&gt;, so the app reads &lt;code&gt;/etc/secrets/db-password&lt;/code&gt; as a plain file. For anything that rotates — database passwords, API keys — volume mounts are the right choice.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The full working stack: Vault with Longhorn persistent storage, auto-unseal CronJob, ESO syncing secrets to K8s, pods consuming via volume mounts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don't use dev mode for anything you care about — persistent storage from the start saves a lot of pain&lt;/li&gt;
&lt;li&gt;Initialize Vault before deploying anything that depends on it — ESO will report sync errors if Vault isn't ready&lt;/li&gt;
&lt;li&gt;Use volume mounts over env vars for secrets that rotate, and make sure your app reads the file on each use rather than caching it&lt;/li&gt;
&lt;li&gt;Test your unseal story before you need it at an inconvenient time&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>vault</category>
      <category>devops</category>
      <category>security</category>
    </item>
  </channel>
</rss>
