<?xml version="1.0"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">

<channel>
	<title>Planet dgplug</title>
	<link>http://planet.dgplug.org/</link>
	<language>en</language>
	<description>Planet dgplug - http://planet.dgplug.org/</description>
	<atom:link rel="self" href="http://planet.dgplug.org/rss20.xml" type="application/rss+xml"/>

<item>
	<title>Sanyam Khurana: Tears of Joy (इतना खुश हुआ कि रो दिया)</title>
	<guid isPermaLink="false">tag:www.sanyamkhurana.com,2026-06-02:/blog/tears-of-joy.html</guid>
	<link>https://www.sanyamkhurana.com/blog/tears-of-joy.html</link>
	<description>&lt;p class=&quot;first last&quot;&gt;A poem about finding peace within oneself-where joy and sorrow blur, and every broken moment becomes a mirror of the soul.&lt;/p&gt;</description>
	<pubDate>Tue, 02 Jun 2026 02:26:00 +0000</pubDate>
</item>
<item>
	<title>Jason Braganza: 2026</title>
	<guid isPermaLink="true">https://janusworx.com/reading/2026/</guid>
	<link>https://janusworx.com/reading/2026/</link>
	<description>&lt;div style=&quot;font-size: 85%;&quot;&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;What do all the stars and daggers after the book titles mean?&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;¶ for &lt;a href=&quot;https://janusworx.com/lindy-books/&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;Lindy books&lt;/a&gt; &lt;br /&gt;
* for the ones I love&lt;br /&gt;
† for most non fiction&lt;br /&gt;
‡ for tech / work / study / reference stuff &lt;br /&gt;
# for alternate media (like audio or video)&lt;br /&gt;
numbers are footnotes&lt;br /&gt;
Some book titles might be repeated (in addition to the annual Lindy reads :)&lt;br /&gt;
After all, &lt;a href=&quot;https://janusworx.com/lindy-books/&quot; rel=&quot;noopener noreferrer&quot; target=&quot;_blank&quot;&gt;we are what we re-read&lt;/a&gt; :)&lt;/p&gt;
&lt;/div&gt;
&lt;br /&gt;

&lt;h3 id=&quot;january&quot;&gt;January&lt;/h3&gt;
&lt;div class=&quot;book-list&quot;&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://therestishistory.com/episodes/&quot;&gt;The Rest is History&lt;/a&gt;, The Nazis at War, Parts I-IV&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;†&lt;/sup&gt;&lt;sup&gt;#&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://podcasts.apple.com/gb/podcast/sherlock-co/id1710121792&quot;&gt;The Second Stain&lt;/a&gt;, Sherlock &amp;amp; Co. Podcast, Season 37&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;#&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://podcasts.apple.com/gb/podcast/sherlock-co/id1710121792&quot;&gt;The Man with the Twisted Lip&lt;/a&gt;, Sherlock &amp;amp; Co. Podcast, Season 38&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;#&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.dancarlin.com/product/hardcore-history-73-mania-for-subjugation-iii/&quot;&gt;Mania for Subjugation III&lt;/a&gt;, Hardcore History, Episode 73&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;†&lt;/sup&gt;&lt;sup&gt;#&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;The Thin Man, Dashiell Hammett&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Sister, Maiden, Monster, Lucy A. Snyder&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Shattered Lands, Sam Dalrymple&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;†&lt;/sup&gt;, &lt;a href=&quot;https://janusworx.com/reading/shattered-lands/&quot;&gt;Related Post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The Psychology of Money, Morgan Housel&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;†&lt;/sup&gt;, &lt;a href=&quot;https://janusworx.com/reading/the-psychology-of-money/&quot;&gt;Related Post&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;History of the Alphabet, Kevin Stroud&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;†&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;A Play of Isaac, Margaret Frazer&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://therestishistory.com/episodes/&quot;&gt;The Rest is History&lt;/a&gt;, Jack the Ripper, Parts I-IV&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;†&lt;/sup&gt;&lt;sup&gt;#&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://podcasts.apple.com/gb/podcast/sherlock-co/id1710121792&quot;&gt;The Muskgrave Ritual&lt;/a&gt;, Sherlock &amp;amp; Co. Podcast, Season 39&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;h3 id=&quot;february&quot;&gt;February&lt;/h3&gt;
&lt;div class=&quot;book-list&quot;&gt;
&lt;ol start=&quot;13&quot;&gt;
&lt;li&gt;The Spy Who Came in from the Cold, John le Carré&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;The Novice’s Tale, Margaret Frazer&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Beyond the Rift, Peter Watts&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;The Servant’s Tale, Margaret Frazer&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Call for the Dead, John le Carré&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;A Murder of Quality, John le Carré&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;The Outlaw’s Tale, Margaret Frazer&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.thedeeplife.com/listen/&quot;&gt;Deep Questions&lt;/a&gt;, Cal Newport, Episodes 381-390&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;†&lt;/sup&gt;&lt;sup&gt;#&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;The Girl with the Dragon Tattoo, Stieg Larsson&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Falco, The Official Companion, Lindsey Davis&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;h3 id=&quot;march&quot;&gt;March&lt;/h3&gt;
&lt;div class=&quot;book-list&quot;&gt;
&lt;ol start=&quot;23&quot;&gt;
&lt;li&gt;The Girl Who Played With Fire, Stieg Larsson&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;The Girl Who Kicked the Hornet’s Nest, Stieg Larsson&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;The Looking Glass War, John le Carré&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Tinker, Tailor, Soldier, Spy, John le Carré&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;The Honourable Schoolboy, John le Carré&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;The Bear and the Nightingale, Katherine Arden&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;The Girl in the Tower, Katherine Arden&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;The Winter of the Witch, Katherine Arden&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;h3 id=&quot;april&quot;&gt;April&lt;/h3&gt;
&lt;div class=&quot;book-list&quot;&gt;
&lt;ol start=&quot;31&quot;&gt;
&lt;li&gt;50 Literature Ideas, You Really Need to Know, John Sutherland&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;†&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.thedeeplife.com/listen/&quot;&gt;Deep Questions&lt;/a&gt;, Cal Newport, Episodes 391-400&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;†&lt;/sup&gt;&lt;sup&gt;#&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Lincoln the Unknown, Dale Carnegie&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;†&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://podcasts.apple.com/in/podcast/empire/id1639561921&quot;&gt;Empire Podcast&lt;/a&gt;, The Bronze Age Apocalypse, Episodes 332-337&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;†&lt;/sup&gt;&lt;sup&gt;#&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://podcasts.apple.com/in/podcast/empire/id1639561921&quot;&gt;Empire Podcast&lt;/a&gt;, Indian Uprising 1857, Episodes 322-329&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;†&lt;/sup&gt;&lt;sup&gt;#&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://podcasts.apple.com/gb/podcast/sherlock-co/id1710121792&quot;&gt;The Beryl Coronet&lt;/a&gt;, Sherlock &amp;amp; Co. Podcast, Season 40&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://podcasts.apple.com/gb/podcast/sherlock-co/id1710121792&quot;&gt;The Stockbroker’s Clerk&lt;/a&gt;, Sherlock &amp;amp; Co. Podcast, Season 41&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://podcasts.apple.com/gb/podcast/sherlock-co/id1710121792&quot;&gt;The Six Napoleons&lt;/a&gt;, Sherlock &amp;amp; Co. Podcast, Season 42&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Songteller, My Life in Lyrics, Dolly Parton&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;†&lt;/sup&gt;&lt;sup&gt;#&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://podcasts.apple.com/in/podcast/empire/id1639561921&quot;&gt;Empire Podcast&lt;/a&gt;, The Middle East: From the Arab Cold War to the Israeli Invasion of Lebanon, Episodes 346-353&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;†&lt;/sup&gt;&lt;sup&gt;#&lt;/sup&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;h3 id=&quot;may&quot;&gt;May&lt;/h3&gt;
&lt;div class=&quot;book-list&quot;&gt;
&lt;ol start=&quot;41&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://podcasts.apple.com/gb/podcast/sherlock-co/id1710121792&quot;&gt;The Three Garridebs&lt;/a&gt;, Sherlock &amp;amp; Co. Podcast, Season 43&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://podcasts.apple.com/gb/podcast/sherlock-co/id1710121792&quot;&gt;The Empty House&lt;/a&gt;, Sherlock &amp;amp; Co. Podcast, Season 44&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Smiley’s People, John le Carré&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://podcasts.apple.com/in/podcast/empire/id1639561921&quot;&gt;Empire Podcast&lt;/a&gt;, Simon Bolivar: the Liberator, Episodes 354-357&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;†&lt;/sup&gt;&lt;sup&gt;#&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.acquired.fm/episodes/vanguard&quot;&gt;Vanguard&lt;/a&gt;, Spring 2026, Episode 3, Acquired Podcast&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;†&lt;/sup&gt;&lt;sup&gt;#&lt;/sup&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;h3 id=&quot;june&quot;&gt;June&lt;/h3&gt;
&lt;div class=&quot;book-list&quot;&gt;
&lt;ol start=&quot;46&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://therestishistory.com/episodes/&quot;&gt;The Rest is History&lt;/a&gt;, The Fall of the Incas, Episodes 644-649&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;†&lt;/sup&gt;&lt;sup&gt;#&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://podcasts.apple.com/in/podcast/empire/id1639561921&quot;&gt;Empire Podcast&lt;/a&gt;, Spice Wars: The Battle of the East India Companies, Episodes 358-360&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;†&lt;/sup&gt;&lt;sup&gt;#&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;Learning Object-Oriented Programming, Design and TDD with Pharo, Stéphane Ducasse &amp;amp; Damien Pollet&lt;sup&gt;*&lt;/sup&gt;&lt;sup&gt;‡&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;The Secret Pilgrim, John le Carré&lt;sup&gt;*&lt;/sup&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;hr style=&quot;margin-left: auto; margin-right: auto; margin-bottom: 40px; margin-top: 50px; width: 100px; border: none; background-color: rgb(238, 238, 238); color: rgb(238, 238, 238); height: 1px;&quot; /&gt;</description>
	<pubDate>Mon, 01 Jun 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Anwesha Das: Swedish OSPO Network Workshop 9: OpenChain in Practice</title>
	<guid isPermaLink="false">https://anweshadas.in/rss/6a14a7e2fc747d0001865102</guid>
	<link>http://anweshadas.in/swedish-ospo-network-workshop-9-openchain-in-practice/</link>
	<description>&lt;p&gt;There are 3 pillars of the open source ecosystem, tecnhnology, community and legal&lt;br /&gt;
It is important to think beyond code -- beyond the pull requests and CI pipelines -- and into the broader questions of how we build, share, and sustain open source software together. The ninth Swedish OSPO Network workshop, hosted by WirelessCar in Gothenburg, was exactly that kind of event.&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-swedish-ospo-network&quot;&gt;What is the Swedish OSPO Network?&lt;/h2&gt;
&lt;p&gt;Before I dive into the workshop itself, a bit of context. The &lt;a href=&quot;https://swedish-ospo-network.se/?ref=anweshadas.in&quot;&gt;Swedish OSPO Network&lt;/a&gt; is an informal network of Swedish organizations, companies, government agencies, and academic institutions, that are building or running Open Source Program Offices (OSPOs). The idea is simple and powerful: people who are figuring out how to use, develop, and contribute to open source in a structured way within their organizations come together, share what they have learned, and help each other navigate the challenges.&lt;/p&gt;
&lt;p&gt;The network operates on shared ownership. Members take turns hosting workshops, and discussions follow the &lt;a href=&quot;https://en.wikipedia.org/wiki/Chatham_House_Rule?ref=anweshadas.in&quot;&gt;Chatham House Rule&lt;/a&gt; to encourage honest, open conversations. The presentations and materials are made publicly available whenever possible. It is open source in spirit, not just in subject matter.&lt;/p&gt;
&lt;h2 id=&quot;what-is-openchain&quot;&gt;What is OpenChain?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://openchainproject.org/?ref=anweshadas.in&quot;&gt;OpenChain&lt;/a&gt; is a Linux Foundation project initiated in the year 2016, intended to bring transparency and consistency open source software&amp;amp;aposs supply chain. OpenChain addresses this by maintaining two ISO standards:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ISO/IEC 5230&lt;/strong&gt;  the international standard for open source license compliance programs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ISO/IEC 18974&lt;/strong&gt;  the industry standard for open source security assurance programs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They provide a practical framework for organizations to establish clear policies, define roles, train their people, and build repeatable processes around open source compliance and security. Over a thousand companies globally use OpenChain resources, and adoption is growing notably, 31% of large German companies already use or plan to adopt the standard.&lt;/p&gt;
&lt;h2 id=&quot;the-kick-off&quot;&gt;The kick off&lt;/h2&gt;
&lt;p&gt;The session was kicked off by walking us through the &quot;what&quot; and &quot;why&quot; behind the network -- reminding us of the vital role Open Source Program Offices play in modern organizational strategy.&lt;/p&gt;
&lt;h2 id=&quot;a-masterclass-on-integrating-open-source-into-automotive-software-lifecycle&quot;&gt;A masterclass on integrating open source into automotive software lifecycle.&lt;/h2&gt;
&lt;p&gt;The approach of the organization rests on three pillars:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Create&lt;/strong&gt; -- building innovative solutions that drive the next generation of digital car services.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use&lt;/strong&gt; -- leveraging the existing open source ecosystem for agility and security.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Contribute&lt;/strong&gt; -- returning value to the communities that support their progress.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What struck me was how the presenter&amp;amp;aposs team have woven compliance, developer productivity, and community engagement into a single, coherent pipeline through their OSPO. It is not just about consuming open source; it is about being a genuine participant in the ecosystem.&lt;/p&gt;
&lt;h3 id=&quot;supply-chain-the-spaghetti-monster&quot;&gt;Supply Chain: The Spaghetti Monster&lt;/h3&gt;
&lt;p&gt;Then we  deangled a complex, and hard to navigate path of Supply Chain security, the spaghetti monster. The speaker walked us through a clear, structured journey of how the OpenChain Project evolved to tame it:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Study and Brainstorm&lt;/strong&gt; identifying the tangled complexities.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Guide&lt;/strong&gt;  creating navigation pathways.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Specification&lt;/strong&gt;  establishing foundational standards.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Standard&lt;/strong&gt; achieving ISO/IEC 18974:2023 certification.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The key takeaway? Using OpenChain is not just about ticking a compliance checkbox. It is about building trust and establishing clarity in processes that were previously opaque. That distinction matters.&lt;/p&gt;
&lt;h3 id=&quot;licensing-first&quot;&gt;Licensing First&lt;/h3&gt;
&lt;p&gt;One discussion that really stayed with me was around software licensing as a quality gate. The room reached a consensus that I think more of the industry needs to hear: &lt;strong&gt;software licenses must be the first check on code before we even look at security, functionality, or performance.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The reasoning is straightforward. Without proper licensing compliance, even the most brilliantly engineered software becomes a liability rather than an asset. Legal usage rights form the foundation upon which everything else is built.&lt;/p&gt;
&lt;p&gt;Integrating OpenChain standards in the open source strategy early on is not just about compliance it establishes trust throughout the supply chain. It was clearly encouraging to hear big organizations talk about it.&lt;/p&gt;
&lt;h3 id=&quot;all-ospos-look-different&quot;&gt;All OSPOs Look Different&lt;/h3&gt;
&lt;p&gt;A theme that ran through the entire day was that there is no one-size-fits-all OSPO. Every organization&amp;amp;aposs open source journey is different. Some are just getting started with a handful of policies; others have mature, centralized functions with open source champions embedded across teams. The workshop featured a practical case study of an organization that transitioned from fragmented, reactive compliance to a centralized OSPO function -- complete with tiered training programs, SBOM requirements in SPDX format, and trust-based policies with clear escalation paths.&lt;br /&gt;
With regulations like the Cyber Resilience Act (CRA) demanding better visibility into dependencies and contribution capabilities, OpenChain provides a framework for implementation the legal rules.&lt;/p&gt;
&lt;h2 id=&quot;looking-back&quot;&gt;Looking Back&lt;/h2&gt;
&lt;p&gt;What I appreciated most about this workshop was the openness. People were genuinely sharing their struggles, their experiments, and their wins. Nobody pretended to have it all figured out. Thank you to &lt;a href=&quot;https://www.linkedin.com/company/wirelesscar/?ref=anweshadas.in&quot;&gt;WirelessCar&lt;/a&gt; for hosting and thank you everyone who shared their experiences and insights.&lt;br /&gt;
Looking foward to the next one!&lt;/p&gt;</description>
	<pubDate>Mon, 25 May 2026 19:55:29 +0000</pubDate>
</item>
<item>
	<title>Jason Braganza: Matthias Endler Built His Own Newsletter Setup</title>
	<guid isPermaLink="true">https://janusworx.com/work/matthias-endler-built-his-own-newsletter-setup/</guid>
	<link>https://janusworx.com/work/matthias-endler-built-his-own-newsletter-setup/</link>
	<description>&lt;div class=&quot;admonition info&quot;&gt;
      &lt;div class=&quot;admonition-header&quot;&gt;&lt;svg viewBox=&quot;0 0 512 512&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM216 336l24 0 0-64-24 0c-13.3 0-24-10.7-24-24s10.7-24 24-24l48 0c13.3 0 24 10.7 24 24l0 88 8 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-80 0c-13.3 0-24-10.7-24-24s10.7-24 24-24zm40-208a32 32 0 1 1 0 64 32 32 0 1 1 0-64z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;
        &lt;span&gt;Intended Audience&lt;/span&gt;
      &lt;/div&gt;
      &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;p&gt;Mostly me (confirmation bias. slight gloating 😂)&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;&lt;br /&gt;

&lt;figure class=&quot;align-center &quot;&gt;
    &lt;img alt=&quot;Rust in Production podcast logo&quot; src=&quot;https://janusworx.com/images/2026/matthias-endler-newsletter-setup-rust-in-production.jpg#center&quot; width=&quot;500px&quot; /&gt; 
&lt;/figure&gt;

&lt;hr style=&quot;margin-left: auto; margin-right: auto; margin-bottom: 40px; margin-top: 50px; width: 100px; border: none; background-color: rgb(238, 238, 238); color: rgb(238, 238, 238); height: 1px;&quot; /&gt;

&lt;p&gt;I’m writing this post today, because I monkeyed with my &lt;a href=&quot;https://janusworx.com/work/found-mjml/&quot;&gt;newsletter template&lt;/a&gt;. &lt;em&gt;&lt;strong&gt;Again!&lt;/strong&gt;&lt;/em&gt;&lt;br /&gt;
So this post is just to make sure there are no more hiccoughs :)&lt;/p&gt;
&lt;p&gt;Matthias Endler, he of the fantastic &lt;a href=&quot;https://corrode.dev/podcast/s06e04-rust4linux/&quot;&gt;Rust in Production podcast&lt;/a&gt; (and the Corrode rust consultancy) just published &lt;a href=&quot;https://endler.dev/2026/newsletter-setup/&quot;&gt;a post on his newsletter setup&lt;/a&gt; and how he went about building it.&lt;/p&gt;
&lt;p&gt;His reasons (and his story) are really similar to mine.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;https://janusworx.com/tags/dgplug/index.xml#fn:1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;br /&gt;
Tinyletter =&amp;gt; Mailchimp =&amp;gt;&lt;br /&gt;
Wanting to have a semblance of control after being burnt =&amp;gt; Self hosting!&lt;/p&gt;
&lt;p&gt;He settled on &lt;a href=&quot;https://www.useplunk.com/&quot;&gt;Plunk&lt;/a&gt;, while I use my &lt;a href=&quot;https://sendy.co&quot;&gt;Sendy&lt;/a&gt; + Amazon SES combo. (they look pretty similar to me)&lt;br /&gt;
Newsletters live in a git controlled repo. Same.&lt;br /&gt;
Write in my favourite editor. Ditto.&lt;br /&gt;
One markdown file per letter. Same pinch!&lt;/p&gt;
&lt;p&gt;The only difference, is his workflow is controlled by a fancy cli, while I depend on ye old copy &amp;amp; paste.&lt;/p&gt;
&lt;p&gt;Having someone with a visible presence do this, hopefully serves as an inspiration to others.&lt;br /&gt;
I just wish more of my nerd kinfolk do this!&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;hr style=&quot;margin-left: auto; margin-right: auto; margin-bottom: 40px; margin-top: 50px; width: 100px; border: none; background-color: rgb(238, 238, 238); color: rgb(238, 238, 238); height: 1px;&quot; /&gt;

Feedback on this post?&lt;br /&gt;
Mail me at &lt;a href=&quot;mailto:feebdback@janusworx.com?subject=%22Feedback on post: Matthias Endler Built His Own Newsletter Setup %22&quot;&gt;feedback at this domain&lt;/a&gt;.
&lt;br /&gt;

&lt;br /&gt;

P.S. Subscribe to my &lt;a href=&quot;https://janusworx.com/subscribe/&quot;&gt;mailing list!&lt;/a&gt;&lt;p&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;except for his audience ofcourse! Which is orders of magnitude larger than my dinky little circle of friends &lt;a class=&quot;footnote-backref&quot; href=&quot;https://janusworx.com/tags/dgplug/index.xml#fnref:1&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description>
	<pubDate>Fri, 22 May 2026 10:43:29 +0000</pubDate>
</item>
<item>
	<title>Jason Braganza: Change!</title>
	<guid isPermaLink="true">https://janusworx.com/personal/change-sara-bareilles/</guid>
	<link>https://janusworx.com/personal/change-sara-bareilles/</link>
	<description>&lt;br /&gt;

&lt;p&gt;&lt;a href=&quot;https://janusworx.com/images/2026/change-sara-bareilles-DSCF2217.jpg&quot;&gt;&lt;/a&gt;&lt;/p&gt;&lt;figure class=&quot;align-center &quot;&gt;&lt;a href=&quot;https://janusworx.com/images/2026/change-sara-bareilles-DSCF2217.jpg&quot;&gt;
    &lt;img alt=&quot;Close up of cherry blossoms on a tree in Paris&quot; src=&quot;https://janusworx.com/images/2026/change-sara-bareilles-DSCF2217-s.jpg#center&quot; width=&quot;500px&quot; /&gt; 
&lt;/a&gt;&lt;/figure&gt;&lt;a href=&quot;https://janusworx.com/images/2026/change-sara-bareilles-DSCF2217.jpg&quot;&gt;
&lt;/a&gt;&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://janusworx.com/images/2026/change-sara-bareilles-DSCF2217.jpg&quot;&gt;Click for a larger pic&lt;/a&gt;&lt;/p&gt;

&lt;hr style=&quot;margin-left: auto; margin-right: auto; margin-bottom: 40px; margin-top: 50px; width: 100px; border: none; background-color: rgb(238, 238, 238); color: rgb(238, 238, 238); height: 1px;&quot; /&gt;

&lt;p&gt;&lt;em&gt;Distill a whole year down into a day&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;Act like we all start over with a pristine slate&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;To get yourself a new life you’ve got to give the other one away&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;And I’m starting to believe, in the power of a name&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;Cause it can’t be a mistake,&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;if I just call it change!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;— &lt;a href=&quot;https://www.youtube.com/watch?v=Gv972gdiu58&quot;&gt;Sara Bareilles, December&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;hr style=&quot;margin-left: auto; margin-right: auto; margin-bottom: 40px; margin-top: 50px; width: 100px; border: none; background-color: rgb(238, 238, 238); color: rgb(238, 238, 238); height: 1px;&quot; /&gt;

Feedback on this post?&lt;br /&gt;
Mail me at &lt;a href=&quot;mailto:feebdback@janusworx.com?subject=%22Feedback on post: Change! %22&quot;&gt;feedback at this domain&lt;/a&gt;.
&lt;br /&gt;

&lt;br /&gt;

P.S. Subscribe to my &lt;a href=&quot;https://janusworx.com/subscribe/&quot;&gt;mailing list!&lt;/a&gt;&lt;p&gt;&lt;/p&gt;
&lt;hr /&gt;</description>
	<pubDate>Fri, 22 May 2026 05:58:30 +0000</pubDate>
</item>
<item>
	<title>Jason Braganza: Found MJML</title>
	<guid isPermaLink="true">https://janusworx.com/work/found-mjml/</guid>
	<link>https://janusworx.com/work/found-mjml/</link>
	<description>&lt;br /&gt;


            
    &lt;div class=&quot;admonition info&quot;&gt;
      &lt;div class=&quot;admonition-header&quot;&gt;&lt;svg viewBox=&quot;0 0 512 512&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM216 336l24 0 0-64-24 0c-13.3 0-24-10.7-24-24s10.7-24 24-24l48 0c13.3 0 24 10.7 24 24l0 88 8 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-80 0c-13.3 0-24-10.7-24-24s10.7-24 24-24zm40-208a32 32 0 1 1 0 64 32 32 0 1 1 0-64z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;
        &lt;span&gt;Intended Audience&lt;/span&gt;
      &lt;/div&gt;
      &lt;div class=&quot;admonition-content&quot;&gt;
        &lt;p&gt;Mostly me.&lt;br /&gt;
Also hopefully, other folks struggling with, or looking for a way to create email newsletters.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;&lt;figure class=&quot;align-center &quot;&gt;
    &lt;img alt=&quot;MJML SVG logo&quot; src=&quot;https://janusworx.com/images/2026/mjml-logo.svg#center&quot; width=&quot;500px&quot; /&gt; 
&lt;/figure&gt;

&lt;hr style=&quot;margin-left: auto; margin-right: auto; margin-bottom: 40px; margin-top: 50px; width: 100px; border: none; background-color: rgb(238, 238, 238); color: rgb(238, 238, 238); height: 1px;&quot; /&gt;

&lt;p&gt;I recently upgraded &lt;a href=&quot;https://sendy.co/&quot;&gt;Sendy&lt;/a&gt;, the software, I’m using to create and send my newsletters.&lt;br /&gt;
(I don’t need the new shiny, or the extra features, but also those folks have been pretty good as far as pricing and functionality go, and I want them to stick around for a long time.)&lt;/p&gt;
&lt;p&gt;The new release, in addition to a refreshed interface, now features a block WYSIWYG editor. And my old template (based on the venerable &lt;a href=&quot;https://github.com/internations/antwort&quot;&gt;Antwort&lt;/a&gt;) that I used to compose my emails broke. What used to be a predictable way of writing emails, now turned into something filled with papercuts. Everything would look alright, but everything was ever so subtly out of place.&lt;/p&gt;
&lt;p&gt;So I went looking for something that I could live with long term once again.&lt;br /&gt;
Since all of this is a personal hobby and I only use all of this to send mail to a handful of my friends, most of the paid options go right out of the window, because. And because I am a control freak, hosted options aren’t a thing for me either.&lt;/p&gt;
&lt;p&gt;Enter &lt;a href=&quot;https://mjml.io/&quot;&gt;MJML&lt;/a&gt;.&lt;br /&gt;
From their website:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;MJML was created in early 2015 by a team of Mailjet developers while they were working on Passport, Mailjet’s drag-and-drop interface for creating responsive emails. Having been knee deep in email for five years, the Mailjet team saw two things: a) email HTML is antiquated and not developer friendly b) a growing trend of email being viewed on mobile and tablet and the number of screens is only increasing. This means that finding a way to code responsive email easily and quickly is pretty important. The team started by creating a new markup language that would abstract the complexity of responsive HTML and automatically generate it. And that’s how MJML was born.&lt;/p&gt;
&lt;p&gt;After learning so much from our users, we wanted to give back to the community by sharing this open-source framework to make responsive email easier and redefine the coding experience once and for all.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It works in the same vein as &lt;a href=&quot;https://revealjs.com/&quot;&gt;revealjs&lt;/a&gt;.&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;https://janusworx.com/tags/dgplug/index.xml#fn:1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;br /&gt;
You install the tool and use their semantic markup to write a document.&lt;br /&gt;
The MJML cli tool, in this case, then renders it to email worthy HTML.&lt;br /&gt;
The &lt;a href=&quot;https://documentation.mjml.io/#mjml-guide&quot;&gt;markup&lt;/a&gt; is simple and well thought out. Writing it is a breeze.&lt;br /&gt;
I used Timo Reymann’s &lt;a href=&quot;https://plugins.jetbrains.com/plugin/16418-mjml-support&quot;&gt;MJML plugin&lt;/a&gt; for Jetbrains editors to help me write, which makes things even easier, since it let’s me preview my work live.&lt;/p&gt;
&lt;p&gt;I took one of their pretty templates, &lt;a href=&quot;https://mjml.io/try-it-live/templates/recast&quot;&gt;Recast&lt;/a&gt; and then stripped it down to meet my needs and match it as closely as I could to my old customised Antwort template.&lt;/p&gt;
&lt;p&gt;Now all I do, is write, copy the HTML into the sendy editor and send. Life is good!&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;hr style=&quot;margin-left: auto; margin-right: auto; margin-bottom: 40px; margin-top: 50px; width: 100px; border: none; background-color: rgb(238, 238, 238); color: rgb(238, 238, 238); height: 1px;&quot; /&gt;

Feedback on this post?&lt;br /&gt;
Mail me at &lt;a href=&quot;mailto:feebdback@janusworx.com?subject=%22Feedback on post: Found MJML %22&quot;&gt;feedback at this domain&lt;/a&gt;.
&lt;br /&gt;

&lt;br /&gt;

P.S. Subscribe to my &lt;a href=&quot;https://janusworx.com/subscribe/&quot;&gt;mailing list!&lt;/a&gt;&lt;p&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;Or does revealjs work in the same vein as mjml? &lt;a class=&quot;footnote-backref&quot; href=&quot;https://janusworx.com/tags/dgplug/index.xml#fnref:1&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description>
	<pubDate>Thu, 21 May 2026 05:21:49 +0000</pubDate>
</item>
<item>
	<title>Jason Braganza: Books I Read in April, 2026</title>
	<guid isPermaLink="true">https://janusworx.com/reading/books-i-read-in-april-2026/</guid>
	<link>https://janusworx.com/reading/books-i-read-in-april-2026/</link>
	<description>&lt;br /&gt;

&lt;figure style=&quot;display: flex;&quot;&gt;
  &lt;img src=&quot;https://janusworx.com/images/2026/dolly-parton-songteller.jpg&quot; /&gt;
&lt;/figure&gt;
&lt;br /&gt;

&lt;p&gt;April was as busy as March, with hardly any time, between returning from Kubecon, catching up with everything and then once again getting ready to visit a client in early May. Did get quite a bit reading done though.&lt;br /&gt;
As you can see above, I was enchanted by the magic of Dolly Parton all this month!&lt;/p&gt;
&lt;hr style=&quot;margin-left: auto; margin-right: auto; margin-bottom: 40px; margin-top: 50px; width: 100px; border: none; background-color: rgb(238, 238, 238); color: rgb(238, 238, 238); height: 1px;&quot; /&gt;

&lt;h3 id=&quot;deep-questions-cal-newport-episodes-391-400&quot;&gt;&lt;a href=&quot;https://www.thedeeplife.com/listen/&quot;&gt;Deep Questions&lt;/a&gt;, Cal Newport, Episodes 391-400&lt;/h3&gt;
&lt;p&gt;I’m going to stop counting these episodes as books now.&lt;br /&gt;
Cal’s getting more prolific and repetitive.&lt;br /&gt;
Neither of which are bad things at all.&lt;br /&gt;
But this means that I now listen to him, like I listen to my old songs or Ziglar tapes.&lt;br /&gt;
Just so that I can hear their voices and remember their principles.&lt;br /&gt;
400 seems to be a lovely place to stop counting.&lt;br /&gt;
His advice and work on the intersection of life and craft, is invaluable to me, and you can be sure, I’ll be listening as long as he is sharing his thoughts.&lt;/p&gt;
&lt;hr style=&quot;margin-left: auto; margin-right: auto; margin-bottom: 40px; margin-top: 50px; width: 100px; border: none; background-color: rgb(238, 238, 238); color: rgb(238, 238, 238); height: 1px;&quot; /&gt;

&lt;h3 id=&quot;lincoln-the-unknown-dale-carnegie&quot;&gt;Lincoln the Unknown, Dale Carnegie&lt;/h3&gt;
&lt;p&gt;This is a book I read when I was a child and when I came across it in a flea market, I picked it up out of sheer delight and nostalgia.&lt;br /&gt;
It presents Lincoln as a moral guide with plenty of stories of his life, his family and his work. No critical or academic study here. It has quite a few facts and a great deal of hagiographic admiration as well.&lt;br /&gt;
I absolutely loved it!&lt;/p&gt;
&lt;hr style=&quot;margin-left: auto; margin-right: auto; margin-bottom: 40px; margin-top: 50px; width: 100px; border: none; background-color: rgb(238, 238, 238); color: rgb(238, 238, 238); height: 1px;&quot; /&gt;

&lt;h3 id=&quot;empire-podcast&quot;&gt;&lt;a href=&quot;https://podcasts.apple.com/in/podcast/empire/id1639561921&quot;&gt;Empire Podcast&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Indian Uprising 1857, Episodes 322-329&lt;/strong&gt;&lt;br /&gt;
The First War of Independence, the Indian Uprising of 1857, the Great Sepoy Mutiny, it goes by so many names.&lt;br /&gt;
This series goes into quite a bit of depth on the events upto and during the war for independence and presents many, many points of view.&lt;br /&gt;
This was a wonderful listen.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Bronze Age Apocalypse, Episodes 332-337&lt;/strong&gt;&lt;br /&gt;
A small series on a old civilisation extant in the Levant and its relationships with other places in the Mediterranean.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Middle East: From the Arab Cold War to the Israeli Invasion of Lebanon, Episodes 346-353&lt;/strong&gt;&lt;br /&gt;
If you want to know all the context for what’s happening in Iran now, go listen to this series. Very insightful.&lt;/p&gt;
&lt;hr style=&quot;margin-left: auto; margin-right: auto; margin-bottom: 40px; margin-top: 50px; width: 100px; border: none; background-color: rgb(238, 238, 238); color: rgb(238, 238, 238); height: 1px;&quot; /&gt;

&lt;h3 id=&quot;the-beryl-coronet-the-stockbrokers-clerk-the-six-napoleons-sherlock--co-podcast-season-40-41--42&quot;&gt;The Beryl Coronet, The Stockbroker’s Clerk, The Six Napoleons, &lt;a href=&quot;https://podcasts.apple.com/gb/podcast/sherlock-co/id1710121792&quot;&gt;Sherlock &amp;amp; Co. Podcast&lt;/a&gt;, Season 40, 41 &amp;amp; 42&lt;/h3&gt;
&lt;p&gt;A series of tiny adventures stringing along a much larger arc. Who is the Spider? Is it Moriarty lurking in the shadows? It’s getting thrillier and thrillier!&lt;/p&gt;
&lt;hr style=&quot;margin-left: auto; margin-right: auto; margin-bottom: 40px; margin-top: 50px; width: 100px; border: none; background-color: rgb(238, 238, 238); color: rgb(238, 238, 238); height: 1px;&quot; /&gt;

&lt;h3 id=&quot;literature-ideas-you-really-need-to-know-john-sutherland&quot;&gt;Literature Ideas, You Really Need to Know, John Sutherland&lt;/h3&gt;
&lt;p&gt;Lots of concepts very simply explained and thought through. Everything I found here, will help me be more introspective about all future (good) books I read. I learned quite a lot. Here’s a bit about classics …&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;‘Classic’ – a debased term?&lt;/strong&gt;&lt;/em&gt; Eliot’s question (what is a classic?) remains tantalizing; and the abuses of the term he joked about are still everywhere. ‘Classic comedy’ is more likely to mean Carry On Up the Khyber than Aristophanes. Football matches, rock-and-roll and tea cakes are all given honorific ‘classic’ status (cigars are also labelled ‘Hamlet’ – but that, like nags called Dante, is something else).&lt;/p&gt;
&lt;p&gt;Overused and abused as the term is, literature still needs it. Properly applied, the idea of ‘classic’ points towards something that we hold to be centrally important – although defining that something is tricky.&lt;/p&gt;
&lt;p&gt;Eliot saw classics as fruit of the society in which they happened. ‘A classic,’ he told his Virgilian audience, ‘can only occur when a civilization is mature; when a language and a literature are mature. And it must be the work of a mature mind.’ He doubtless made this lofty statement in an auditorium where the blackout blinds were pulled down, as part of the protective measures against German bombers aiming to blast the assembled classicists to pieces. Whatever epithet one chose in 1944&lt;sup id=&quot;fnref:1&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;https://janusworx.com/tags/dgplug/index.xml#fn:1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; for the civilization that had produced Virgil (currently under the heel of Mussolini), ‘mature’ would not be it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;The classic and empire:&lt;/strong&gt;&lt;/em&gt; [Frank] Kermode was sharper in his sociology than Eliot. It was not a civilization but an empire – with all the temporal (and, if necessary, brutal) cultural power imperialism implies – that supplied the foundation for the classic. If a language is, as linguists like to joke, a dialect with an army behind it, then classic literature is writing with an imperium behind it. This is easily enough tested with reference to the European Union, which currently has some 27 member countries.
Which of those countries can be said to have classic literatures, as opposed to some impressive works of literature? The answer would be those which – before the twentieth-century winds of change blew – had great empires (Britain, France, Spain, Italy, Portugal, Germany, Holland, Austria, Belgium). Does Luxembourg have its classics? Or Moldova? Where are their Shakespeares, Racines or Cervantes?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;In a brilliant critical move  Kermode argues that it is the very pliability of the classic that is its essence. It ‘accommodates’ – makes itself at home – wherever and whenever it finds itself. It is the classic’s ability to be both antique, yet modern, its infinite – but never anarchic – plurality that defines it. A work like King Lear, Kermode argues, ‘subsists in change, by being patient of interpretation’. Every generation will read, or understand, King Lear differently insofar as every generation is different from its predecessors. No final version, or interpretation, of the play can be achieved. But every generation will find its own satisfactory interpretation. And the classic is tolerant of each and every different explanation of itself.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;The condensed idea&lt;/strong&gt;&lt;/em&gt;&lt;br /&gt;
The classic is the gold standard of literature – but all that glistens is not classic&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr style=&quot;margin-left: auto; margin-right: auto; margin-bottom: 40px; margin-top: 50px; width: 100px; border: none; background-color: rgb(238, 238, 238); color: rgb(238, 238, 238); height: 1px;&quot; /&gt;

&lt;h3 id=&quot;songteller-my-life-in-lyrics-dolly-parton&quot;&gt;Songteller: My Life in Lyrics, Dolly Parton&lt;/h3&gt;
&lt;p&gt;I listened to this on audio first, because I wanted to hear Dolly sing, just as I wanted to hear Sara Bareilles tell of her songs in her book and Judi Dench speak of her perfomances in hers. And then I went and bought it as an ebook as well, because I wanted to see all the pictures as well :)&lt;br /&gt;
My childhood was Dolly Parton (and Kenny Rogers and Willie Nelson and other country artists). And I probably listened to her as she hit her stride as an extremely successful solo artist. Because I had no idea of her variety show on television and all her work with Porter Wagoner for close to two decades before her solo work, seventies onwards.&lt;br /&gt;
I loved hearing her voice, humming along and laughing along and telling stories of her dad and her husband and all her big family and the struggles she faced and the way she handled fame, showcased in short, rapid vignettes. If you love her music, this is a must listen. Dolly’s amazing!&lt;/p&gt;
&lt;p&gt;Dolly, talking about her song, “The Sacrifice” as well as reminiscing on her journey.&lt;sup id=&quot;fnref:2&quot;&gt;&lt;a class=&quot;footnote-ref&quot; href=&quot;https://janusworx.com/tags/dgplug/index.xml#fn:2&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a song that I wrote that just came out of my heart and soul, my gut. Sometimes you wonder if you’ve made all the wise choices. Would you do things differently if you could?&lt;/p&gt;
&lt;p&gt;People say, “How come all of this success happened to you?” I say, “Because I sacrificed whatever I had to in order to get it.” You can’t veer off into this and that. You can’t lose your momentum if you’ve got a dream and a focus. I always felt like God was directing me. So I’m not going to let up until He says, “Stop.” I just keep going, like a horse with blinders on.&lt;/p&gt;
&lt;p&gt;I wrote “The Sacrifice” because somebody asked me that question. Well, the answer is, I gave up time with family and friends. I gave up vacations for work. I “carried my pail.” Like the song says, “You don’t drink the water, if you don’t drill the well.” One of my favorite lines I ever wrote is, “I was gonna be rich, no matter how much it cost / And I was going to win, no matter how much I lost.”&lt;/p&gt;
&lt;p&gt;It’s only in the wee hours, when you’re fading off to sleep, that you ask, “Is it worth the sacrifice?” I think I probably wouldn’t have done anything different, because I believe that this is what I was supposed to do. Who am I not to sacrifice to make things better for the people here that I am responsible for?&lt;/p&gt;
&lt;p&gt;Yes, I would do it all again. No doubt about it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;/p&gt;&lt;hr style=&quot;margin-left: auto; margin-right: auto; margin-bottom: 40px; margin-top: 50px; width: 100px; border: none; background-color: rgb(238, 238, 238); color: rgb(238, 238, 238); height: 1px;&quot; /&gt;

Feedback on this post?&lt;br /&gt;
Mail me at &lt;a href=&quot;mailto:feebdback@janusworx.com?subject=%22Feedback on post: Books I Read in April, 2026 %22&quot;&gt;feedback at this domain&lt;/a&gt;.
&lt;br /&gt;

&lt;br /&gt;

P.S. Subscribe to my &lt;a href=&quot;https://janusworx.com/subscribe/&quot;&gt;mailing list!&lt;/a&gt;&lt;p&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&quot;fn:1&quot;&gt;
&lt;p&gt;Eliot was addressing the Virgil Society on the subject of classics in 1944 &lt;a class=&quot;footnote-backref&quot; href=&quot;https://janusworx.com/tags/dgplug/index.xml#fnref:1&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn:2&quot;&gt;
&lt;p&gt;This text closes the audiobook. But I’ve chosen the paraphrased text from the ebook though. Dolly’s actual ramble while lovely to listen to, meanders somewhat before it gets to her very emphatic No doubt about it :) &lt;a class=&quot;footnote-backref&quot; href=&quot;https://janusworx.com/tags/dgplug/index.xml#fnref:2&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description>
	<pubDate>Sat, 16 May 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Robin Schubert: Happy Digital Independence Day</title>
	<guid isPermaLink="false">https://blog.schubisu.de/blog/2026/1/index.gmi</guid>
	<link>https://blog.schubisu.de/blog/2026/1</link>
	<description>Happy Digital Independence Day
  
  
  


&lt;h1 id=&quot;happy-digital-independence-day&quot;&gt;Happy Digital Independence
Day&lt;/h1&gt;
&lt;pre class=&quot;metadata/yaml&quot;&gt;&lt;code&gt;title: Happy Digital Independence Day
published: 2026-05-03&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.schubisu.de/blog/2026/1/../../2025/03&quot;&gt;previous [‘I quit
everything’]&lt;/a&gt; &lt;a href=&quot;https://blog.schubisu.de/blog/2026/1/../&quot;&gt;parent
directory&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I assume that every one at least in my bubble has thought about it
quite a bit. How can we manage to get rid of Google, Microsoft, Amazon,
Meta and all those big tech creeps that are so greedy for our personal
data and that got us locked-in so tightly into their services and
hardware in our daily lives?&lt;/p&gt;
&lt;p&gt;When I quit Facebook there were two immediate results from that
action:&lt;/p&gt;
&lt;ol class=&quot;incremental&quot; type=&quot;1&quot;&gt;
&lt;li&gt;I felt good about ditching that rabbit hole and closing my account,
no longer supporting the Nazi-cyborg CEO with my presence on his
platform.&lt;/li&gt;
&lt;li&gt;I lost contact to a bunch of people that I wouldn’t call my closest
friends but that I still enjoyed reading from time to time.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;However, that was some years ago and one thing has notably changed
since then; people started to care a lot more. Since the US has gone
completely out of control (or is being controlled by an orange,
blabbering maniac, which sounds just the same to me), people started to
wonder if it may have been not the best idea to entrust their whole
private and work lives to some US data traders with a kill switch.&lt;/p&gt;
&lt;p&gt;So last year Marc-Uwe Kling, a famous author in Germany, pitched an
idea that with the potential to make a change, and to make the change
easy, fun, and applicable for the broad masses, not just for tech
nerds:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cultur.social/@marcuwekling/114796763555334470&quot;&gt;Idea
of the Digital Independence Day (German)&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-digital-independence-day&quot;&gt;What is the Digital
Independence Day&lt;/h2&gt;
&lt;p&gt;The idea is to go in small steps, to take these steps together and to
keep going.&lt;/p&gt;
&lt;p&gt;Every first Sunday of the month, people are encouraged to think about
there digital dependencies. If you’re still stuck with WhatsApp and you
feel like exploring an alternative, simply install e.g. Signal as an
alternative on your phone ALONG with WhatsApp. No need to switch now and
to switch hard and to push others to do so. Simply check out the
alternative, maybe use it in parallel to your existing app and find out
how it works for you.&lt;/p&gt;
&lt;p&gt;It’s just a matter of few minutes to install an additional app, or to
switch your default search engine from Google to e.g. Startpage. Small
steps. See how it goes, and continue next month. And the most important
of all: Share your success :D post it on your social media or in your
status or wherever you like to let people know.&lt;/p&gt;
&lt;p&gt;The official website provides recipes to make these small changes;
may it be messaging, email, social networks, office or whatever you hack
away with on your digital devices.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://di.day&quot;&gt;DI Day&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(pronounced “dee day” in “German English”, as in Dooms Day, pun
intended)&lt;/p&gt;
&lt;h2 id=&quot;sounds-cool-can-i-participate&quot;&gt;Sounds cool, can I
participate?&lt;/h2&gt;
&lt;p&gt;Absolutely. It’s easy, too. You can just do it; every first Sunday in
the month, look at your service stack. Are you still using that Gmail
address to let Google read your private communication? Do you really
still hang around on this puddle of Nazi-AIslop X? Maybe it’s time to
try and test an alternative!&lt;/p&gt;
&lt;p&gt;Check out our hashtags on Mastodon to get an idea what’s currently
going on here:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://mastodon.social/tags/diday&quot;&gt;#DIday&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://mastodon.social/tags/didit&quot;&gt;#DIDit&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://mastodon.social/tags/dutgemacht&quot;&gt;#DUTgemacht&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;#DUTgemacht for “Digital Unabhängigkeitstag done” which sounds like
“gut gemacht” (‘well done’ in German).&lt;/p&gt;
&lt;p&gt;And the community has gone wild, it’s a movement happening here. Find
a community online or in your vicinity. Maybe your local community is
even giving workshops and advice for people who need some assistance and
they need your help. If not, maybe you’ll just be the one to initiate
it!&lt;/p&gt;
&lt;p&gt;We’ve been offering support for all interested people in our local
hackspace in Münster since January this year and it’s awesome. Without
even much of publicity there have been more visitors than I’d have
expected; people that have had enough of being bossed around and
exploited by tech oligarchs but just didn’t know where or how to start
to make a change. We’ve had quite some people who were interested in
installing Linux on their machines and just needed a little
guidance.&lt;/p&gt;
&lt;p&gt;If I had to ditch Facebook once again, I’d do it that way. Let people
know where to find me next, invite my bubble to check out the new place
together with me. Making the change together is much easier and much
more fun!&lt;/p&gt;
&lt;p&gt;For today there are 103 di.day events in 5 countries announced. I
admit the vast majority is still in Germany, but it doesn’t have to stay
that way. It’s a digital problem and it’s a global problem, so borders
will not matter at all.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://diday.org/en/&quot;&gt;DIDay events&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We celebrate our digital independence day, growing more independent
every month with a growing community every month. Today it’s DIDAY
again; check it out, participate, share it!&lt;/p&gt;</description>
	<pubDate>Sun, 03 May 2026 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Kushal Das: A git sign bug</title>
	<guid isPermaLink="true">https://kushaldas.in/posts/a-git-sign-bug.html</guid>
	<link>https://kushaldas.in/posts/a-git-sign-bug.html</link>
	<description>&lt;p&gt;While working on the new &lt;code&gt;git signing&lt;/code&gt; feature for
&lt;a href=&quot;https://github.com/tumpaproject/tumpa-cli&quot;&gt;tumpa-cli&lt;/a&gt; I noticed that some of
the commits can not be verified. For a moment I freaked out and then thought it
must be a problem in my code. But, I could not dig enough. Opus 4.7 helped me
to find the eaxct commit in git's history and a reproducer. I reported the &lt;a href=&quot;https://lore.kernel.org/git/4d5d04e2-49c4-4781-a289-f8cf79570643@sunet.se/T/#u&quot;&gt;issue to the
maintainers&lt;/a&gt;
and they are working on a fix.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;\xc2\xa7&lt;/code&gt; aka &lt;code&gt;§&lt;/code&gt; was the cause for me.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;msg.txt body&lt;/th&gt;&lt;th&gt;sign stdin (tee'd)&lt;/th&gt;&lt;th&gt;stored commit body&lt;/th&gt;&lt;th&gt;verify&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;git 2.43&lt;/strong&gt; (host)&lt;/td&gt;&lt;td&gt;&lt;code&gt;... 20 a7 0a&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;... 20 c2 a7 0a&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;... 20 c2 a7 0a&lt;/code&gt;&lt;/td&gt;&lt;td&gt;OK&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;git 2.53&lt;/strong&gt; (CI, docker)&lt;/td&gt;&lt;td&gt;&lt;code&gt;... 20 a7 0a&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;... 20 a7 0a&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;... 20 c2 a7 0a&lt;/code&gt;&lt;/td&gt;&lt;td&gt;BAD&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;git 2.43 transcoded the message to UTF-8 BEFORE calling the signer;
signer and storage saw the same bytes (&lt;code&gt;c2 a7&lt;/code&gt;). git 2.53 hands the
signer the RAW bytes (&lt;code&gt;a7&lt;/code&gt;) and transcodes only on the way to the
commit object (&lt;code&gt;c2 a7&lt;/code&gt;). The invariant &quot;bytes fed to &lt;code&gt;gpg.program&lt;/code&gt; at
sign time equal the bytes a verifier sees when it reads the commit
back&quot; is broken.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git config i18n.commitEncoding iso-8859-1&lt;/code&gt; is supposed to be the configuration
if we have non &lt;code&gt;UTF-8&lt;/code&gt; characters. But, I never knew about this configuration
before I found the bug.&lt;/p&gt;
&lt;p&gt;I want to thank my friends in Anthropic for letting me use the tools and
techonology to keep building. &lt;/p&gt;</description>
	<pubDate>Sun, 26 Apr 2026 08:58:55 +0000</pubDate>
</item>
<item>
	<title>Sanyam Khurana: Teaching getpass How to Handle Keyboard Shortcuts</title>
	<guid isPermaLink="false">tag:www.sanyamkhurana.com,2026-03-31:/blog/cpython-getpass-keyboard-shortcuts.html</guid>
	<link>https://www.sanyamkhurana.com/blog/cpython-getpass-keyboard-shortcuts.html</link>
	<description>&lt;p class=&quot;first last&quot;&gt;How I fixed keyboard shortcuts in Python's getpass module when using echo_char, turning a raw character reader into a proper line editor.&lt;/p&gt;</description>
	<pubDate>Mon, 30 Mar 2026 18:30:00 +0000</pubDate>
</item>
<item>
	<title>Kushal Das: In the land of XML</title>
	<guid isPermaLink="true">https://kushaldas.in/posts/in-the-land-of-xml.html</guid>
	<link>https://kushaldas.in/posts/in-the-land-of-xml.html</link>
	<description>&lt;p&gt;One of the major thing at &lt;a href=&quot;https://sunet.se&quot;&gt;work&lt;/a&gt; is XML, due to all things
identity. Yes, XML and SAML are very much alive.
&lt;a href=&quot;https://www.sunet.se/services/identifiering/swamid&quot;&gt;SWAMID&lt;/a&gt; is the identity
fedeation for research and higher education in Sweden and &lt;a href=&quot;https://edugain.org&quot;&gt;edusgain&lt;/a&gt; which is
the global identify federation around the world connected 80+ pariticipaaant
federations connecting over 10k identify and service providers. And these are based on SAML.&lt;/p&gt;
&lt;p&gt;In the last few weeks  I released two libraries  in Rust and then python bindings for the same using pyo3.
&lt;a href=&quot;https://crates.io/crates/uppsala&quot;&gt;uppsala&lt;/a&gt; is the zero dependency XML library and &lt;a href=&quot;https://pypi.org/project/pyuppsala/&quot;&gt;pyuppsala&lt;/a&gt; is the python binding.&lt;/p&gt;
&lt;h2&gt;Features of uppsala/pyuppsala&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;XML 1.0 parsing&lt;/strong&gt; with full well-formedness checking&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Namespace-aware DOM&lt;/strong&gt; with tree mutation (create, append, insert, remove, detach)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;XPath 1.0&lt;/strong&gt; evaluation (all axes, functions, predicates)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;XSD validation&lt;/strong&gt; (structures + datatypes, 40+ built-in types, facets, complex types)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;XSD regex&lt;/strong&gt; pattern matching (Unicode categories, blocks, character class subtraction)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Imperative XML builder&lt;/strong&gt; (&lt;code&gt;XmlWriter&lt;/code&gt;) for constructing output without a DOM&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Serialization&lt;/strong&gt; with pretty-printing, compact output, and streaming to files&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automatic encoding detection&lt;/strong&gt; for UTF-8 and UTF-16 (LE/BE)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Read the &lt;a href=&quot;https://pyuppsala.rtfd.io&quot;&gt;full documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://crates.io/crates/bergshamra&quot;&gt;bergshamra&lt;/a&gt; is the pure Rust XML Security
library implementing the W3C XML Digital Signatures (XML-DSig), XML Encryption
(XML-Enc), and XML Canonicalization (C14N) specifications. Built entirely on
the RustCrypto ecosystem with &lt;a href=&quot;https://crates.io/crates/uppsala&quot;&gt;Uppsala&lt;/a&gt; for
XML parsing, and &lt;a href=&quot;https://pypi.org/project/pybergshamra&quot;&gt;pybergshamra&lt;/a&gt; is the python binding.&lt;/p&gt;
&lt;h2&gt;Features of bergshamra/pybergshamra&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;XML Digital Signatures&lt;/strong&gt; — sign and verify (enveloped, enveloping, detached)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;XML Encryption&lt;/strong&gt; — encrypt and decrypt (element, content, key wrapping, key transport, multi-recipient)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;XML Canonicalization&lt;/strong&gt; — all 6 W3C C14N variants (inclusive/exclusive, with/without comments, 1.0/1.1) with document-subset filtering via XPath&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;X.509 certificate chain&lt;/strong&gt; — validation with expiry, trust anchors, CRL revocation, chain building&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Post-quantum signatures&lt;/strong&gt; — ML-DSA (FIPS 204) and SLH-DSA (FIPS 205) with context strings&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EdDSA&lt;/strong&gt; — Ed25519 signatures (RFC 8032)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Key agreement&lt;/strong&gt; — ECDH-ES (P-256/P-384/P-521), X25519, DH-ES (X9.42 finite-field)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Key derivation&lt;/strong&gt; — ConcatKDF, HKDF (SHA-256/384/512), PBKDF2&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RSA-OAEP&lt;/strong&gt; — configurable digest (SHA-1/224/256/384/512), MGF1, and OAEPparams&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HMAC truncation&lt;/strong&gt; — HMACOutputLength with CVE-2009-0217 minimum length protection&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SAML support&lt;/strong&gt; — SAML v1.1 &lt;code&gt;AssertionID&lt;/code&gt; attribute as default ID, &lt;code&gt;cid:&lt;/code&gt; URI scheme for WS-Security MIME references&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CipherReference&lt;/strong&gt; — resolve encrypted content via URI with XPath and Base64 transforms&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;XPath&lt;/strong&gt; — XPath, XPath Filter 2.0, XPointer for reference processing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;XSLT&lt;/strong&gt; — identity transform and minimal XSLT for document-subset operations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OPC Relationship Transform&lt;/strong&gt; — for Office Open XML signatures (ECMA-376 Part 2)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Key formats&lt;/strong&gt; — PEM, DER, PKCS#8 (plain and encrypted), PKCS#12, X.509 (PEM and DER), xmlsec keys.xml, raw symmetric keys&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;KeyInfo resolution&lt;/strong&gt; — KeyName, X509Certificate (multi-cert chain with leaf detection), X509IssuerSerial, RSA/EC/DSA KeyValue, DEREncodedKeyValue, RetrievalMethod, EncryptedKey, KeyInfoReference&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;#![forbid(unsafe_code)]&lt;/code&gt;&lt;/strong&gt; across every crate&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Supported algorithms&lt;/h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Category&lt;/th&gt;&lt;th&gt;Algorithms&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Digest&lt;/td&gt;&lt;td&gt;SHA-1, SHA-224/256/384/512, SHA3-224/256/384/512, MD5†, RIPEMD-160†&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Signature (RSA)&lt;/td&gt;&lt;td&gt;RSA PKCS#1 v1.5 (SHA-1/224/256/384/512, MD5†, RIPEMD-160†), RSA-PSS (SHA-1/224/256/384/512, SHA3-224/256/384/512)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Signature (EC)&lt;/td&gt;&lt;td&gt;ECDSA (P-256/P-384/P-521 × SHA-1/224/256/384/512, SHA3-224/256/384/512, RIPEMD-160†)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Signature (other)&lt;/td&gt;&lt;td&gt;DSA (SHA-1, SHA-256), Ed25519, HMAC (SHA-1/224/256/384/512, MD5†, RIPEMD-160†)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Post-quantum&lt;/td&gt;&lt;td&gt;ML-DSA-44/65/87 (FIPS 204), SLH-DSA SHA2-128f/128s/192f/192s/256f/256s (FIPS 205)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Block cipher&lt;/td&gt;&lt;td&gt;AES-128/192/256-CBC, AES-128/192/256-GCM, 3DES-CBC&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Key wrap&lt;/td&gt;&lt;td&gt;AES-KW-128/192/256 (RFC 3394), 3DES-KW (RFC 3217)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Key transport&lt;/td&gt;&lt;td&gt;RSA PKCS#1 v1.5, RSA-OAEP (SHA-1/224/256/384/512 digest, MGF1-SHA-1/224/256/384/512)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Key agreement&lt;/td&gt;&lt;td&gt;ECDH-ES (P-256/P-384/P-521), X25519, DH-ES (X9.42)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Key derivation&lt;/td&gt;&lt;td&gt;ConcatKDF, HKDF (SHA-256/384/512), PBKDF2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;C14N&lt;/td&gt;&lt;td&gt;Inclusive 1.0/1.1, Exclusive 1.0, each ± comments&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Transforms&lt;/td&gt;&lt;td&gt;Enveloped signature, Base64, XPath, XPath Filter 2.0, XSLT (identity), OPC Relationship&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Key formats&lt;/td&gt;&lt;td&gt;PEM, DER, PKCS#8, PKCS#12, X.509, xmlsec keys.xml, raw HMAC/AES/3DES&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;† MD5 and RIPEMD-160 are behind the &lt;code&gt;legacy-algorithms&lt;/code&gt; feature flag.&lt;/p&gt;
&lt;h2&gt;xmlsec test suite compatibility&lt;/h2&gt;
&lt;p&gt;Bergshamra is tested against the full
&lt;a href=&quot;https://www.aleksey.com/xmlsec/&quot;&gt;xmlsec&lt;/a&gt; interoperability test suite
(1157 test steps across DSig and Enc). These are the same tests used by
the xmlsec1 C library, covering test vectors from the W3C, Merlin, Aleksey,
IAIK, NIST, and Phaos interop suites.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Suite&lt;/th&gt;&lt;th&gt;Passed&lt;/th&gt;&lt;th&gt;Failed&lt;/th&gt;&lt;th&gt;Total&lt;/th&gt;&lt;th&gt;Pass Rate&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Enc&lt;/td&gt;&lt;td&gt;701&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;701&lt;/td&gt;&lt;td&gt;100%&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;DSig&lt;/td&gt;&lt;td&gt;447&lt;/td&gt;&lt;td&gt;9&lt;/td&gt;&lt;td&gt;456&lt;/td&gt;&lt;td&gt;98%&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;1148&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;9&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;1157&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;99.2%&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;The 9 DSig failures are GOST algorithm tests (GOST R 34.10-2001,
GOST R 34.10-2012-256, GOST R 34.10-2012-512) which require special
OS cryptographic libraries not available in the RustCrypto ecosystem.&lt;/p&gt;
&lt;p&gt;These are the libraries, you will see the tools/services built on top of
these in the coming months hopefully.&lt;/p&gt;</description>
	<pubDate>Mon, 09 Mar 2026 07:22:53 +0000</pubDate>
</item>
<item>
	<title>Titas Dey: The Degenerate Way to Count in Binary</title>
	<guid isPermaLink="true">https://blogs.dgplug.org/titas/the-degenerate-way-to-count-in-binary</guid>
	<link>https://blogs.dgplug.org/titas/the-degenerate-way-to-count-in-binary</link>
	<description>&lt;p&gt;I don't know if it's worth it to know how to count in binary. Irrespective of it I'll share some observations I made a year back.&lt;/p&gt;

&lt;h2 id=&quot;how-numbers-are-written&quot;&gt;How Numbers are Written ....&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Radix(orBase)&lt;/strong&gt; :  The number of unique symbols or digits in a system. If a system has a radix &lt;em&gt;R&lt;/em&gt;, the allowable digits are &lt;em&gt;0&lt;/em&gt; through &lt;em&gt;R-1&lt;/em&gt;.
i.e. radix 5 means, digits from 0 to 4 .&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Counting is done recursively , here for radix 5 the numbers will be written as:
0,1,2,3,4,10,11,12,13,14,20,21,22,23,24,30... so on&lt;/p&gt;

&lt;p&gt;0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15.... This is for decimal numbers&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;We can observe (10) in base 5 == (5) in base 10&lt;/p&gt;

&lt;p&gt;The maximum unique digits in base 5 is five, so counting from 0-4 we exhaust all our options , to write the next number we need another digit. Hence we bring a 1 ahead and reset the numbers right of it.
The numbers after 4 becomes 10,11,12,13,14 again we exhaust all the options with 1 fixed , so we make it 2 and reset the numbers in right of it to 0, now we'll have five more numbers 20,21,22,23,24 this goes on till 44. Here we've exhausted all numbers that can be created with 2 spaces so we'll need another space and the next number will be (100)base5.&lt;/p&gt;

&lt;p&gt;The main observation is :
&lt;strong&gt;For Radix (N) the maximum unique numbers by r digits == N^r&lt;/strong&gt;
eg. Maximum unique numbers in decimal number system by 2 digits ==&amp;gt; 10^2 = 100
0 to 99
&lt;strong&gt;For Radix (N) a number written in the format (N-1) (N-1) (N-1) (N-1) ...for r terms  = N^r – 1&lt;/strong&gt;
&lt;strong&gt;(N-1) 00000.... upto r zeros = N^r&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;eg. (444) base 5 = (5^3-1) i.e 124 in decimal
eg. (1000) base 9 = 9^3 = 729&lt;/p&gt;

&lt;h2 id=&quot;counting-in-binary&quot;&gt;Counting in Binary&lt;/h2&gt;

&lt;p&gt;Now that we're clear with the basics&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1&amp;gt; consecutive 1's written r times = 2^r-1&lt;/strong&gt;
eg. (1111)&lt;sub&gt;2&lt;/sub&gt; =&amp;gt; 2^4-1 = 15&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2&amp;gt; 1 followed by r zeros = 2^r&lt;/strong&gt;
eg. (100000)&lt;sub&gt;2&lt;/sub&gt; =&amp;gt; 2^5 = 32&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3&amp;gt; Sticking 1 zero after a number means multiplying with 2&lt;/strong&gt;
eg. (10)&lt;sub&gt;2&lt;/sub&gt; = 2
then (100)&lt;sub&gt;2&lt;/sub&gt; = 2*2 = 4&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4&amp;gt; Sticking one 1 after a number means multiplying with 2 + 1&lt;/strong&gt;
eg. (111)&lt;sub&gt;2&lt;/sub&gt; = 7
then (1111)&lt;sub&gt;2&lt;/sub&gt; = 7 X 2 +1 = 15&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5&amp;gt; Memorise the first 4 binary numbers&lt;/strong&gt;
– (0)&lt;sub&gt;2&lt;/sub&gt; = 0
– (1)&lt;sub&gt;2&lt;/sub&gt; = 1
– (10)&lt;sub&gt;2&lt;/sub&gt; = 2
– (11)&lt;sub&gt;2&lt;/sub&gt; = 3&lt;/p&gt;

&lt;p&gt;Some Examples:&lt;/p&gt;

&lt;p&gt;eg.1) Say we have (11001)&lt;sub&gt;2&lt;/sub&gt;,
&amp;gt; we know 11 = 3 then the number = ((3 x 2) x 2)x2+1 = 25&lt;/p&gt;

&lt;p&gt;eg.2) (11110110)&lt;sub&gt;2&lt;/sub&gt;
&amp;gt; we know 1111 = 15 (i.e 2^4-1) , the number will be ((((15x2)x2+1)x2+1)x2) = 246&lt;/p&gt;

&lt;p&gt;eg.3) Convert 211 to binary
&amp;gt; we can think 211 = 255-44
&amp;gt; The 255 = 2^8-1 , so 8 consecutive 1s, and we remove 44 i.e(32+8+4) from it ,
&amp;gt; (11111111)&lt;sub&gt;2&lt;/sub&gt; is 255, now we remove the 1s from 2^5 , 2^3, 2^2 s places and leave them with 0s
&amp;gt; (11010011)&lt;sub&gt;2&lt;/sub&gt; is 211&lt;/p&gt;

&lt;h2 id=&quot;thats-it&quot;&gt;Thats it&lt;/h2&gt;

&lt;p&gt;Thats pretty much it. These are just patterns , once you see them you can't unsee them.
Whether it's actually useful , I still don't know.&lt;/p&gt;</description>
	<pubDate>Sat, 07 Mar 2026 00:42:38 +0000</pubDate>
</item>
<item>
	<title>Farhaan Bukhsh: Hacking Chinese Toy Drone(A17)</title>
	<guid isPermaLink="true">https://journal.farhaan.me/hacking-chinese-toy-dronea17</guid>
	<link>https://journal.farhaan.me/hacking-chinese-toy-dronea17</link>
	<description>&lt;p&gt;During our time at &lt;a href=&quot;https://sciencehackday.in/&quot; target=&quot;_blank&quot;&gt;SHD India 2025&lt;/a&gt; we were about to teach the hackers/kids to fly drones. &lt;a href=&quot;https://x.com/jithinbp_&quot; target=&quot;_blank&quot;&gt;Jithin&lt;/a&gt; sourced about 20 drones, and we were really excited to not only fly them but to see how they would perform. These drones were &lt;a href=&quot;https://www.amazon.in/Foldable-Quadcopter-Altitude-Photography-Beginner/dp/B0FLQMQGMD&quot; target=&quot;_blank&quot;&gt;not very expensive compared&lt;/a&gt; to the industrial-quality drones we have. These were Toy-Drones, and given that kids were going to fly these, they had to be durable, and we needed to prepare ourselves to loose few of them during the process. I was very excited to get my hands on these incredible machines, and that excitement peaked when Jithin asked Saptak and me to hack on these drones in SHD.&lt;/p&gt;
&lt;p&gt;He wanted us to control the drones programmatically. Once we do that and reverse engineer the connection and commands, it opens up an array of possibilities. We could swarm up the drones and make them do tricks, we can improve the object avoidance, and we can build gesture control and object tracking.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;alt&quot; class=&quot;image--center mx-auto&quot; src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1770211052297/05b6560b-c905-4895-a6dd-bb02ebadfb5b.jpeg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This led us to our 3-day streak of taking the stab at controlling this drone with a Python program. First things first, we searched the internet to see if someone had done something like this before. To our surprise, the answer was “YES“ :P And a bunch of people have blogged about it, too. But unfortunately, no one has done this for this specific model. &lt;a href=&quot;https://blog.horner.tj/hacking-chinese-drones-for-fun-and-no-profit/&quot; target=&quot;_blank&quot;&gt;TJ&lt;/a&gt; had this amazing blog that gave us hope of achieving this feat.&lt;/p&gt;
&lt;p&gt;The first thing we saw was that this model has an Android app that is used to get the camera stream, and fortunately, it can also be used to control the drone. Why, fortunately, you may ask? The answer is simple if it can be controlled through a mobile device, which insinuates that there is some kind of digital signal that is being passed to the drones, and in a lot of cases, these are network calls. This gets us to the possibility that we can somehow tap in with an MITM attack and see what is being sent to the drone from the phone. Since this was my Android phone and we wanted to sniff the packets that this phone is sending to the drone, we tried finding a &lt;a href=&quot;https://www.wireshark.org/&quot; target=&quot;_blank&quot;&gt;Wireshark&lt;/a&gt; equivalent for Android Phones and we landed up on &lt;a href=&quot;https://github.com/emanuele-f/PCAPdroid&quot; target=&quot;_blank&quot;&gt;PCAPdroid&lt;/a&gt;, which helped us to capture the packets that are being sent to the drone.&lt;/p&gt;
&lt;p&gt;The understanding we had till now was that there is a WIFI module in the drone, which creates an open hotspot that can be used to connect the phone to and then using the &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.cooingdv.kyufo&amp;amp;hl=en_IN&quot; target=&quot;_blank&quot;&gt;KY UFO&lt;/a&gt; app, the signal gets relayed to the WIFI module, which then gets translated to the instructions set for the drone.&lt;/p&gt;
&lt;p&gt;This understanding helped us to get a clear idea of what is going on; we had to dig deeper to see how this is happening and how we use this flow to achieve a programmable drone. When we tried capturing packets using PCAPdroid, we could see a stream of packets not just from KY UFO application but from the plethora of applications that I have on my phone. PCAPdroid has a way to target a particular application. We changed our settings to tap into the packets that are being sent by KY UFO, and we found out that my phone was being too chatty with the drone. The number of packets was way too high; we got a dump of packets.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;PCAPdroid screenshot show source ip, destination ip and ports&quot; class=&quot;image--center mx-auto&quot; src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1770214759795/30806e52-ed91-4ed0-9337-34f17c6b8d5d.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We got something that we were interested in the &lt;code&gt;Destination IP&lt;/code&gt; and &lt;code&gt;port&lt;/code&gt;, we observed that there were two IP addresses and two different port as well. One of them is used to receive commands for the drone and the other one streams the video from the camera. Now we wanted to find out which one is doing what function. One approach that we took was to reverse engineer the android app itself, we used &lt;a href=&quot;https://github.com/skylot/jadx&quot; target=&quot;_blank&quot;&gt;jadx&lt;/a&gt; to deobfusicate the APK, but it failed since we were not able to get the right APK file for the application. Now we had to find another way to figure out how to find out the same information. We can’t install install wireshark on the android phone but ….. we can install the KY UFO app on the android emulator and then we can capture the packets that are being sent by the application from the laptop to the drone. One of the biggest challenge was to download the emulator on SHD’s wifi connection, it took some time for me to download the emulator as well as the related packages. Once that was done there was an issue to connect the emulator to the internet or the WIFI module of the drone. We figured this out late and night and the drone flew for the first time from the laptop and we could gather the packets very easily. The setup helped us out very much since we can see the application and the packets it is emitting side by side.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;wireshark and emulator opened side by side&quot; class=&quot;image--center mx-auto&quot; src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1770232510700/1684c1ab-3b85-4963-87e2-b0c88144baa8.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;In this setup we have wireshark on one side and the android application on other, this enabled us to observe the packets and sniff them. We were able to see these packets and were able to observe the bytes that the application was sending. But ….. the applications was too chatty it was sending so many packtes that we were not able to find out the packets that were actually doing the actions. Wireshark came to our rescue, &lt;a href=&quot;https://saptaks.website/&quot; target=&quot;_blank&quot;&gt;Saptak&lt;/a&gt; figured out that we can filter the packets with the value that we are getting.&lt;/p&gt;
&lt;p&gt;Till now we had figured out that it’s sending &lt;code&gt;21 bytes&lt;/code&gt; of the form&lt;/p&gt;
&lt;p&gt;&lt;code&gt;03:66:14:80:80:80:80:01:02:00:00:00:00:00:00:00:00:00:00:03:99&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;We figured out the the header remain constant : &lt;code&gt;03:66&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Footer also remain constant: &lt;code&gt;:99&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Padding is about 10 bytes, the zeros you see in the middle this is to future proof the protocol.&lt;/p&gt;
&lt;div class=&quot;embed-wrapper&quot;&gt;&lt;div class=&quot;embed-loading&quot;&gt;&lt;div class=&quot;loadingRow&quot;&gt;&lt;/div&gt;&lt;div class=&quot;loadingRow&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;a class=&quot;embed-card&quot; href=&quot;https://x.com/jithinbp_/status/2007282586679423224?ref_src=twsrc^tfw|twcamp^tweetembed|twterm^2007282586679423224|twgr^600e54a2c89680e8c2cf1f0ca3e2b4a066fe7e05|twcon^s1_&amp;amp;ref_url=https%3A%2F%2Fpublish.twitter.com%2F%3Furl%3Dhttps%3A%2F%2Ftwitter.com%2Fjithinbp_%2Fstatus%2F2007282586679423224&quot;&gt;https://x.com/jithinbp_/status/2007282586679423224?ref_src=twsrc^tfw|twcamp^tweetembed|twterm^2007282586679423224|twgr^600e54a2c89680e8c2cf1f0ca3e2b4a066fe7e05|twcon^s1_&amp;amp;ref_url=https%3A%2F%2Fpublish.twitter.com%2F%3Furl%3Dhttps%3A%2F%2Ftwitter.com%2Fjithinbp_%2Fstatus%2F2007282586679423224&lt;/a&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Now we had to figure out the rest we still don’t know how to move up, down, left and right. We don’t know how to turn(i.e yaw) and there is a bunch of features like headless mode, one touch take-off. We spend the night thinking about it and then Saptak applied the filter where we plan to sniff all the packets which do not have this data. So our query in Wireshark was:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;(data.data != 03:66:14:80:80:80:80:00:02:00:00:00:00:00:00:00:00:00:00:03:99)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;And voila! The doors opened, we were able to see a lot of changed packets, a bit more sniffing and we found the data for one-touch take off was &lt;code&gt;03:66:14:80:80:80:80:01:02:00:00:00:00:00:00:00:00:00:00:03:99&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;When trying to create a UDP connection over the &lt;code&gt;Destination IP&lt;/code&gt; on &lt;code&gt;port&lt;/code&gt; and send the bytes, nothing happened and then we saw the data packets and they were being sent in a cluster of 10 packets with some delay.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;lang-python&quot;&gt;
    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;one_touch&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;self&lt;/span&gt;):&lt;/span&gt;
        &lt;span class=&quot;hljs-comment&quot;&gt;# 03:66:14:80:80:80:80:01:02:00:00:00:00:00:00:00:00:00:00:03:99&lt;/span&gt;
        self.reset()
        self.basebytes[&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;] = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;
        self.basebytes[&lt;span class=&quot;hljs-number&quot;&gt;-2&lt;/span&gt;] = &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;
        print(&lt;span class=&quot;hljs-string&quot;&gt;&quot;taking off&quot;&lt;/span&gt;)
        print(self.basebytes)
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; range(&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;):
            self.send_udp_command(bytes(bytearray(&lt;span class=&quot;hljs-string&quot;&gt;b'\x03'&lt;/span&gt;) + self.basebytes))
            time.sleep(&lt;span class=&quot;hljs-number&quot;&gt;0.01&lt;/span&gt;)
        self.reset()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There it was, our sweet sweet “Eureka!“ moment, the drone flapped it’s wing and we screamed “It’s alive“!&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;alt&quot; class=&quot;image--center mx-auto&quot; src=&quot;https://media1.giphy.com/media/v1.Y2lkPTc5MGI3NjExeXhpOWQ4OW84ODc5MnE3cHpic2M4bnQ3eWhrcnh1ejM0cjl1d3N3YSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/vmv47p4zksWDC/giphy.gif&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Now it was flying, but we didn’t write code for it to land, so we had to turn it upside down to switch it off but this amount of time and effort was fruitful since we got it to fly. Then after this, we have to figure out direction, left, right, forward and backward.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;alt&quot; class=&quot;image--center mx-auto&quot; src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1770268353006/b30ec473-3a4d-4baf-bb36-6df615041ad6.jpeg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We managed to do this cleverly, we already had the &lt;code&gt;Emulator+Wireshark&lt;/code&gt; setup so for each of the movement we capture and saved the packet file. We had one for up, one for down, one for left and one for right. We filtered out packets for each of these directions and were able to code it through. The funny part is for each of these we had to do manual testing, like literally going in the field, we crashed the drones so many times that we stopped feeling bad about it. Finally, we got it to a point that with one drone we were able to program a flying pattern.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;lang-python&quot;&gt;    &lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;pattern&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;self&lt;/span&gt;):&lt;/span&gt;
        print(&lt;span class=&quot;hljs-string&quot;&gt;&quot;Pattern executing...&quot;&lt;/span&gt;)
        &lt;span class=&quot;hljs-comment&quot;&gt;#go forward&lt;/span&gt;
        self.go_forward()
        time.sleep(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)
        self.go_back()
        time.sleep(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)
        self.go_left()
        time.sleep(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)
        self.go_right()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this looks something like&lt;/p&gt;
&lt;div class=&quot;embed-wrapper&quot;&gt;&lt;div class=&quot;embed-loading&quot;&gt;&lt;div class=&quot;loadingRow&quot;&gt;&lt;/div&gt;&lt;div class=&quot;loadingRow&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;a class=&quot;embed-card&quot; href=&quot;https://x.com/fhackdroid/status/2019288114381164801?s=20&quot;&gt;https://x.com/fhackdroid/status/2019288114381164801?s=20&lt;/a&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;We had a lot of fun hacking on this and we learnt a lot of things while doing this hack about protocols We have a work in progress code at &lt;a href=&quot;https://github.com/SaptakS/turbodrone/tree/a17&quot; target=&quot;_blank&quot;&gt;this fork&lt;/a&gt;. We will be cleaning this a lot and put up the wireshark export file for anyone to have a look at. We do have a bunch of issues with the code and it’s not perfect yet, we faced a bunch of issues:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Left yaw was not working as expected&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We struggled to fix acceleration&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It drastically gains a lot of height when we toggle the byte&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After coming back form SHD I was able to reverse engineer the android app in JadX and I got some really beautiful insights.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;alt&quot; class=&quot;image--center mx-auto&quot; src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1770271656719/42bb8ebe-d35c-4809-b97f-a2c4f4c47ec4.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I am not able to figure out exactly what byte does what and the range it can take, I was also able to figure out the headless mode switch, hence will be making those changes next. Feel free to ping me to talk more about this and leave a comment. &lt;strong&gt;Till then Happy Hacking!&lt;/strong&gt;&lt;/p&gt;</description>
	<pubDate>Thu, 05 Feb 2026 06:13:59 +0000</pubDate>
        <enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1770271787804/c1820fda-a736-4517-a82a-32f0a100798a.jpeg" length="0" type="image/jpeg"/>
</item>
<item>
	<title>Kushal Das: replyfast a python module for signal</title>
	<guid isPermaLink="true">https://kushaldas.in/posts/replyfast-a-python-module-for-signal.html</guid>
	<link>https://kushaldas.in/posts/replyfast-a-python-module-for-signal.html</link>
	<description>&lt;p&gt;&lt;a href=&quot;https://github.com/kushaldas/replyfast&quot;&gt;replyfast&lt;/a&gt; is a Python module to receive and send messages on &lt;a href=&quot;https://signal.org/&quot;&gt;Signal&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can install it via &lt;/p&gt;
&lt;p&gt;&lt;code&gt;python3 -m pip install replyfast&lt;/code&gt; &lt;/p&gt;
&lt;p&gt;or &lt;/p&gt;
&lt;p&gt;&lt;code&gt;uv pip install replyfast&lt;/code&gt; &lt;/p&gt;
&lt;p&gt;I have to add Windows builds to CI though.&lt;/p&gt;
&lt;p&gt;I have a &lt;a href=&quot;https://github.com/kushaldas/replyfast/blob/main/register.py&quot;&gt;script&lt;/a&gt; to help you to register as a device, and
then you can send and receive messages.&lt;/p&gt;
&lt;p&gt;I have a &lt;a href=&quot;https://github.com/kushaldas/replyfast/blob/main/examples/demo_bot.py&quot;&gt;demo bot&lt;/a&gt; which shows both sending and rreceiving messages, and also how to schedule work following the &lt;code&gt;crontab&lt;/code&gt; syntaxt.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-Python&quot;&gt;    scheduler.register(
        &quot;*/5 * * * *&quot;,
        send_disk_usage,
        args=(client,),
        name=&quot;disk-usage&quot;,
    )
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is all possible due to the &lt;a href=&quot;https://github.com/whisperfish/presage&quot;&gt;presage&lt;/a&gt; library written in Rust.&lt;/p&gt;</description>
	<pubDate>Mon, 26 Jan 2026 12:16:49 +0000</pubDate>
</item>
<item>
	<title>Titas Dey: Asymptotic Analysis : Big-Oh Notation</title>
	<guid isPermaLink="true">https://blogs.dgplug.org/titas/asymptotic-analysis-big-oh-notation</guid>
	<link>https://blogs.dgplug.org/titas/asymptotic-analysis-big-oh-notation</link>
	<description>&lt;p&gt;Been learning about asymptotic analysis.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Definition&lt;/strong&gt;: Asymptotic analysis is the study of the growth of an algorithm’s running time or space requirement as a function of the input size &lt;strong&gt;n&lt;/strong&gt;, for large values of &lt;strong&gt;n&lt;/strong&gt;, while ignoring constant factors and lower-order terms.&lt;/p&gt;

&lt;p&gt;In other words, we analyze &lt;strong&gt;how the resource consumption of an algorithm scales as the problem size becomes large&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time Complexity != Time taken by the algorithm to run&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Time complexity is a function &lt;strong&gt;f(n)&lt;/strong&gt; that represents the number of elementary operations performed by an algorithm as a function of input size &lt;strong&gt;n ∈ ℕ&lt;/strong&gt;.&lt;/p&gt;

&lt;h4 id=&quot;t-n-number-of-primitive-steps-executed-for-input-size-n&quot;&gt;T(n) = number of primitive steps executed for input size n&lt;/h4&gt;
&lt;ul&gt;&lt;li&gt;&lt;p&gt;&lt;strong&gt;Asymptotic analysis is independent of&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Hardware specifications&lt;/li&gt;
&lt;li&gt;Programming language&lt;/li&gt;
&lt;li&gt;Operating system and runtime environment&lt;/li&gt;
&lt;li&gt;Input distribution (for a fixed &lt;strong&gt;n&lt;/strong&gt;)&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;big-oh-notation-o-notation&quot;&gt;Big-Oh Notation (O-notation)&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Definition:&lt;/strong&gt; Let f(n) and g(n) be functions mapping positive integers to positive real numbers. We say that g(n) is O(f(n)) (read “g of n is big-oh of f of n”) if there exist positive constants c ∈ ℝ⁺ and n₀ ∈ ℕ such that:&lt;/p&gt;

&lt;p&gt;g(n) ≤ c·f(n) ∀ n ≥ n₀&lt;/p&gt;

&lt;p&gt;The function f(n) is called an asymptotic upper bound for g(n). Intuitively, this means that g(n) grows no faster than f(n), up to a constant multiplicative factor, for sufficiently large values of n.&lt;/p&gt;

&lt;p&gt;Visually , if we plot both g(n) and f(n) and can find some point n₀ in the input axis beyond which c·f(n) always stays above g(n). Then g(n) is O(f(n)).
i.e We use Big-Oh if we are concerned with the &lt;strong&gt;worst case&lt;/strong&gt; performance of the algorithm&lt;/p&gt;

&lt;p&gt;eg:&lt;/p&gt;

&lt;p&gt;Say f(n) = 3n² + 5n + 10 , g(n) = n². g(n) = O(f(n)) &amp;amp; f(n) = O(g(n))&lt;/p&gt;

&lt;p&gt;If we analyse this&lt;/p&gt;

&lt;p&gt;We need to find constants c ∈ ℝ⁺ and n₀ ∈ ℕ such that:&lt;/p&gt;

&lt;p&gt;f(n) ≤ c·g(n) ∀ n ≥ n₀&lt;/p&gt;

&lt;p&gt;Substituting:
3n² + 5n + 10 ≤ c·n²&lt;/p&gt;

&lt;p&gt;For n ≥ 1:
– 5n ≤ 5n²
– 10 ≤ 10n²&lt;/p&gt;

&lt;p&gt;Therefore:
3n² + 5n + 10 ≤ 3n² + 5n² + 10n² = 18n²&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt; Choose c = 18 and n₀ = 1. Then f(n) ≤ 18·g(n) ∀ n ≥ 1.&lt;/p&gt;

&lt;p&gt;Hence, f(n) = O(g(n)) or more specifically, f(n) = O(n²).&lt;/p&gt;

&lt;p&gt;Again
(n) ≤ c·f(n) ∀ n ≥ n₀&lt;/p&gt;

&lt;p&gt;Substituting:
n² ≤ c(3n² + 5n + 10)&lt;/p&gt;

&lt;p&gt;Since f(n) = 3n² + 5n + 10 &amp;gt; 3n² for all n ≥ 1, we have:&lt;/p&gt;

&lt;p&gt;n² ≤ 3n² + 5n + 10&lt;/p&gt;

&lt;p&gt;This is clearly true for all n ≥ 1.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt; Choose c = 1 and n₀ = 1. Then g(n) ≤ 1·f(n) ∀ n ≥ 1.&lt;/p&gt;

&lt;p&gt;Hence, g(n) = O(f(n)).&lt;/p&gt;

&lt;h2 id=&quot;big-oh-represents-a-set-of-functions&quot;&gt;Big-Oh Represents a Set of Functions&lt;/h2&gt;

&lt;p&gt;Say , some T(n) = n³ then&lt;br /&gt;
3n² + 5n + 10 = O(T(n))..................i&lt;br /&gt;
5n+7 = O(T(n)).........................ii&lt;br /&gt;
log(n) = O(T(n))_____iii&lt;/p&gt;

&lt;p&gt;if we analytically approach eq(i),eq(ii),eq(iii). All 3 are &lt;strong&gt;True&lt;/strong&gt;
But eq(i) != eq(ii) != eq(iii)&lt;/p&gt;

&lt;p&gt;When we write &lt;strong&gt;f(n) = O(g(n))&lt;/strong&gt;, the &lt;strong&gt;”=”&lt;/strong&gt; is &lt;strong&gt;not&lt;/strong&gt; a true equality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;More Precisely:&lt;/strong&gt; O(g(n)) represents an &lt;strong&gt;infinite set&lt;/strong&gt; of all functions that grow no faster than g(n). So &lt;strong&gt;f(n) = O(g(n))&lt;/strong&gt; really means &lt;strong&gt;f(n) ∈ O(g(n))&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; O(n²) is the set containing functions like:
– n²
– 3n² + 5n + 10
– n² + 100n
– 50n + 1000
– 5 (constant)
– log n&lt;/p&gt;

&lt;p&gt;All these functions belong to the set O(n²) because they all grow no faster than n².&lt;/p&gt;

&lt;p&gt;When we write O(n²), we're saying that as the input size n becomes very large, the running time grows at most proportionally to n². The constant factors and lower-order terms become negligible in comparison to the dominant term, which is why we drop them in Big-Oh notation. For instance, an algorithm that takes 3n² + 5n + 10 operations is simply O(n²) because the n² term dominates as n approaches infinity.&lt;/p&gt;

&lt;p&gt;i.e: We simply ignore the lower order and constant terms when were trying to find the time complexity in Big-Oh&lt;/p&gt;

&lt;hr /&gt;

&lt;h4 id=&quot;some-commonly-seen-cases&quot;&gt;Some Commonly Seen Cases&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;O(1) – Constant Time&lt;/strong&gt;: These operations take the same amount of time regardless of input size. Accessing an array element by index, performing arithmetic operations, and returning a value are all O(1) operations. No matter if our array has 10 elements or 10 million elements, accessing the element at index 5 takes the same time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O(log n) – Logarithmic Time&lt;/strong&gt;: Algorithms that repeatedly divide the problem space in half exhibit logarithmic complexity. Binary search is the classic example, where we eliminate half of the remaining elements with each comparison. As n doubles, the running time increases by only a constant amount.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O(n) – Linear Time&lt;/strong&gt;: When we must examine every element exactly once, we have linear complexity. A simple loop that processes each element in an array demonstrates O(n) behavior. If we double the input size, the running time doubles as well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O(n log n) – Linearithmic Time&lt;/strong&gt;: Efficient sorting algorithms like merge sort and heap sort operate in O(n log n) time. This complexity arises when we perform a logarithmic number of linear operations or divide-and-conquer with linear merging.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O(n²) – Quadratic Time&lt;/strong&gt;: Nested loops where each loop runs n times typically result in quadratic complexity. Simple sorting algorithms like bubble sort and selection sort fall into this category. Doubling the input size quadruples the running time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O(n³) – Cubic Time&lt;/strong&gt;: Triple-nested loops often produce cubic complexity. Matrix multiplication using the naive algorithm is a prime example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O(2ⁿ) – Exponential Time&lt;/strong&gt;: The recursive Fibonacci function is a classic example, where each call branches into two more calls. The running time doubles with each increment of n, making it impractical for even moderately sized inputs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O(n!) – Factorial Time&lt;/strong&gt;: Generating all permutations of n elements produces factorial complexity. For n = 10, that's 3,628,800 operations. Yes calculated that in my head,absolutely did not google.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O(1) &amp;lt; O(log n) &amp;lt; O(n) &amp;lt; O(n log n) &amp;lt; O(n²) &amp;lt; O(n³) &amp;lt; O(2ⁿ) &amp;lt; O(n!)&lt;/strong&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;analyzing-some-algorithms&quot;&gt;Analyzing Some Algorithms&lt;/h2&gt;

&lt;h3 id=&quot;example-1-array-sum&quot;&gt;Example 1: Array Sum&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def array_sum(arr):
    total = 0
    for element in arr:
        total += element
    return total
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The loop runs once per element. Each iteration does constant work.
&lt;strong&gt;Time complexity: O(n)&lt;/strong&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;example-2-finding-maximum-element&quot;&gt;Example 2: Finding Maximum Element&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def find_max(arr):
    if len(arr) == 0:
        return None
    max_val = arr[0]
    for i in range(1, len(arr)):
        if arr[i] &amp;gt; max_val:
            max_val = arr[i]
    return max_val
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Single pass through the array with constant-time operations per iteration.
&lt;strong&gt;Time complexity: O(n)&lt;/strong&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;example-3-bubble-sort&quot;&gt;Example 3: Bubble Sort&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def bubble_sort(arr):
    n = len(arr)
    for i in range(n):
        for j in range(n - i - 1):
            if arr[j] &amp;gt; arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Nested loops result in roughly n² comparisons.
&lt;strong&gt;Time complexity: O(n²)&lt;/strong&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;analyzing-a-slightly-more-complex-program&quot;&gt;Analyzing a Slightly More Complex Program&lt;/h2&gt;

&lt;h3 id=&quot;example-4-binary-search&quot;&gt;Example 4: Binary Search&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;def binary_search(arr, target):
    left = 0
    right = len(arr) - 1
    
    while left &amp;lt;= right:
        mid = (left + right) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] &amp;lt; target:
            left = mid + 1
        else:
            right = mid - 1
    return -1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Initially, the search space has size n. After each iteration:
– 1st iteration: n elements
– 2nd iteration: n/2 elements
– 3rd iteration: n/4 elements
– kth iteration: n/2^(k-1) elements&lt;/p&gt;

&lt;p&gt;The loop continues until the search space is reduced to 1 element or becomes empty. We need to find k such that:&lt;/p&gt;

&lt;p&gt;n/2^(k-1) ≤ 1&lt;/p&gt;

&lt;p&gt;Solving for k:
– n ≤ 2^(k-1)&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;p&gt;log₂(n) ≤ k – 1&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;k ≥ log₂(n) + 1&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Therefore, the loop executes at most &lt;strong&gt;⌈log₂(n)⌉ + 1&lt;/strong&gt; times (ceiling of log₂(n) plus 1).&lt;/p&gt;

&lt;p&gt;Since each iteration performs O(1) operations (comparisons, assignments, arithmetic), the total time complexity is : &lt;strong&gt;T(n) = O(1) + O(log n)·O(1) + O(1) = O(log n)&lt;/strong&gt; .&lt;/p&gt;

&lt;p&gt;i.e &lt;strong&gt;T(n) = O(log(n)) for Binary Search&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion:&lt;/h3&gt;
&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Big-Oh gives an upper bound on how an algorithm scales as input size increases&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;We analyse for n → ∞&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Constant terms and lower order terms are ignored&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;print(&quot;Titas,Signing Out!&quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;hr /&gt;</description>
	<pubDate>Fri, 09 Jan 2026 19:59:56 +0000</pubDate>
</item>
<item>
	<title>Kushal Das: Introducing EktuPy</title>
	<guid isPermaLink="true">https://kushaldas.in/posts/introducing-ektupy.html</guid>
	<link>https://kushaldas.in/posts/introducing-ektupy.html</link>
	<description>&lt;p&gt;Py (daughter) is now 11 years old, and she spends a lot of time on Scratch,
makes beautiful and fun things. But, she thinks she is not a programmer as she
is moving blocks and not typing code like us. I had questions for long time
about how to move this Scratch generation into programming in general via
Python. &lt;a href=&quot;https://ektupy.org&quot;&gt;EktuPy&lt;/a&gt; is my probable solution.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Home page&quot; src=&quot;https://kushaldas.in/images/ektupy/homepage01.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;In simple words, we have an editor to write code in the left, and a Canvas/stage on the left.
You can do all the similar things you do on scratch here, I have a list of examples in the editor.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Hello World&quot; src=&quot;https://kushaldas.in/images/ektupy/helloworld.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We use &lt;a href=&quot;https://pyscript.net/&quot;&gt;PyScript&lt;/a&gt; and thanks to
&lt;a href=&quot;https://astral.sh&quot;&gt;Astral&lt;/a&gt; we have both &lt;a href=&quot;https://docs.astral.sh/ruff/&quot;&gt;Ruff&lt;/a&gt;
and &lt;a href=&quot;https://docs.astral.sh/ty/&quot;&gt;ty&lt;/a&gt; for LSP/linting support in the editor
(using webassembly). The whole code is executing on the browser of the user.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Drawing via keyboard&quot; src=&quot;https://kushaldas.in/images/ektupy/drawing_withkeyboard.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Drawing via pen&quot; src=&quot;https://kushaldas.in/images/ektupy/drawing_pen.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Pong&quot; src=&quot;https://kushaldas.in/images/ektupy/pong.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Yesterday I took part in the monthly &lt;a href=&quot;https://www.youtube.com/watch?v=6Bp_VXowFv4&quot;&gt;PyScript Fun call&lt;/a&gt;
because &lt;a href=&quot;https://ntoll.org&quot;&gt;Nicholas&lt;/a&gt; reminded me, had fun to demonstrate it
there and watched what others are building.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Two Sprites&quot; src=&quot;https://kushaldas.in/images/ektupy/two_sprites.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The first time Py pocked around for 1:30 hours, she gave me 11 bugs, and next
for 5 minutes and asked me to get tutorials, she did not want to read the
&lt;a href=&quot;https://docs.ektupy.org&quot;&gt;documentation&lt;/a&gt;. So, for every example in the editor
we have tutorials, not too detailed yet, but good enough to start.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Tutorial&quot; src=&quot;https://kushaldas.in/images/ektupy/tutorial.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You can create an account and save your programs. You can share them as public
from your dashboard, then others can find those in the
&lt;a href=&quot;https://beta.ektupy.org/explore/&quot;&gt;explorepage&lt;/a&gt; and run the code or remix if they want.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;Space shooter&quot; src=&quot;https://kushaldas.in/images/ektupy/space_shooter.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I am super nostalgic about &lt;a href=&quot;https://beta.ektupy.org/share/8d5bb6a3ecf594cfb9e168ae7f9091b9/&quot;&gt;one implementation&lt;/a&gt; :)&lt;/p&gt;
&lt;p&gt;Oh, because I think kids may not have to learn about &lt;code&gt;async&lt;/code&gt; programming in this
platform, calls like &lt;code&gt;wait()&lt;/code&gt; or &lt;code&gt;ask()&lt;/code&gt; or &lt;code&gt;play_sound_until_done()&lt;/code&gt; or
&lt;code&gt;wait_until()&lt;/code&gt; are all synchronous for the edtior, and then some AST
transformer adds the &lt;code&gt;async/await&lt;/code&gt; as needed. &lt;/p&gt;
&lt;p&gt;Feel free to try this out, share the link to your kid or teachers/parents you
know. Let me know how to improve. I will publish the codebase, a
&lt;a href=&quot;https://www.djangoproject.com/&quot;&gt;Django&lt;/a&gt; application with proper license and
hopefully we can make it even better togather.&lt;/p&gt;
&lt;p&gt;This project was not possible without all the work done before, including
Scratch, or &lt;a href=&quot;https://codemirror.net/&quot;&gt;CodeMirror&lt;/a&gt; for the edtior,
&lt;a href=&quot;https://pyscript.net/&quot;&gt;PyScript&lt;/a&gt; / &lt;a href=&quot;https://pyodide.org/en/stable/&quot;&gt;PyOdide&lt;/a&gt;,
the bigger Python community and
&lt;a href=&quot;https://en.wikipedia.org/wiki/Claude_(language_model)&quot;&gt;Claude/Opus4.5&lt;/a&gt; for
incredicable TypeScript/Javascript help :)&lt;/p&gt;</description>
	<pubDate>Fri, 09 Jan 2026 06:49:21 +0000</pubDate>
</item>
<item>
	<title>Kushal Das: 2025 blog review</title>
	<guid isPermaLink="true">https://kushaldas.in/posts/2025-blog-review.html</guid>
	<link>https://kushaldas.in/posts/2025-blog-review.html</link>
	<description>&lt;p&gt;After &lt;a href=&quot;https://kushaldas.in/2005.html&quot;&gt;2005&lt;/a&gt; again in &lt;a href=&quot;https://kushaldas.in/2025.html&quot;&gt;2025&lt;/a&gt; I wrote only 8 blog posts.
The year was difficult in many different ways. But, from September things
became a bit better. I could not do a lot of things which I thought I would do,
or rather I promised to do.&lt;/p&gt;
&lt;p&gt;I hoping to catch up on those promises in the coming months. That not only
includes blog posts on vairous things I am writing/building, but also I have a
huge backlog of photos to work on and publish.&lt;/p&gt;</description>
	<pubDate>Tue, 06 Jan 2026 08:34:20 +0000</pubDate>
</item>
<item>
	<title>Farhaan Bukhsh: Year End Review - 2025</title>
	<guid isPermaLink="true">https://journal.farhaan.me/year-end-review-2025</guid>
	<link>https://journal.farhaan.me/year-end-review-2025</link>
	<description>&lt;p&gt;This year was full of surprises, mostly pleasant ones; the year was filled with friendships and travels. Towards the end of last year, &lt;a href=&quot;https://x.com/kranirudha&quot; target=&quot;_blank&quot;&gt;Anirudha&lt;/a&gt; and I started working on Rust and tried picking it up. He started a project called &lt;a href=&quot;https://github.com/anistark/feluda&quot; target=&quot;_blank&quot;&gt;Feluda&lt;/a&gt;, and I started contributing to it. In no time, the project evolved beautifully. This prompted us to work on various niches, including &lt;a href=&quot;https://github.com/anistark/wasmrun&quot; target=&quot;_blank&quot;&gt;WASM&lt;/a&gt;. I had to mention this since this was one of the backdrops for me this year, where I was able to express myself apart from what I do for my day job. We were able to collaborate and bring these projects up.&lt;/p&gt;
&lt;p&gt;The year was full of fun, a lot of firsts for me as well. It’s been a year since we shifted from our old place. Shabnam made a lot of effort to find this house and made it into a place where we can live and build it into our little home. This year, we were able to do a little old friends’ reunion. Rana and Rajeev planned to come to Bangalore this April, and Anant and I were already here. We had a really great time talking, roaming around and catching up. This time was a lot of fun.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;alt&quot; class=&quot;image--center mx-auto&quot; src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1767375369859/6ce5091c-a97d-417e-9b12-4c4a0e2868df.jpeg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This was followed by meeting the family. This year, it was my first time to give a &lt;a href=&quot;https://www.youtube.com/watch?v=qes-hzyVIGU&amp;amp;t=314s&quot; target=&quot;_blank&quot;&gt;talk&lt;/a&gt; at &lt;a href=&quot;https://ep2025.europython.eu/&quot; target=&quot;_blank&quot;&gt;EuroPython&lt;/a&gt;, and fortunately, the Open edX conference happened in France, so we took this opportunity and turned it into a Europe trip. We started with Normandy, where it was my work week with &lt;a href=&quot;https://opencraft.com/&quot; target=&quot;_blank&quot;&gt;OpenCraft&lt;/a&gt;; we literally stayed in a castle, all thanks to &lt;a href=&quot;https://www.youtube.com/watch?v=b87_yr0S8W4&quot; target=&quot;_blank&quot;&gt;Xavier&lt;/a&gt; for organising it. I spoke at the Open edX conference in France about this amazing feature called &lt;a href=&quot;https://www.youtube.com/watch?v=U33wPcoaILQ&quot; target=&quot;_blank&quot;&gt;incontext-metrics&lt;/a&gt; which we developed. It was a wonderful time meeting all the people in the community and talking about Open edX and where we are headed.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;alt&quot; class=&quot;image--center mx-auto&quot; src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1767375711959/1356eec2-595b-4f68-9805-aaab87ec7761.jpeg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We explored Paris and oh my my! Every stroll feels like a history walk. Such amazing architecture and such a vibrant culture and food.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;alt&quot; class=&quot;image--center mx-auto&quot; src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1767376317462/8e3c918c-96f0-46bd-b8e0-cfdb8ca97d16.jpeg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We spent about a month in Europe exploring the Netherlands, Germany, Austria and the Czech Republic. Although I am mentioning these countries but we could just explore a city or two at max. There is so much that these countries have to offer. This trip was a trip of a lifetime. The last leg of this trip was Prague. Anirudha and I were speaking at EuroPython, where we literally met our heroes, people who have made Python such an amazing language. They were so humble and so approachable; we were like kids in a candy store. We also met &lt;a href=&quot;https://x.com/kushaldas&quot; target=&quot;_blank&quot;&gt;Kushal&lt;/a&gt; after such a long time. I was delighted to meet him and hack with him after such a long time.&lt;/p&gt;
&lt;div class=&quot;embed-wrapper&quot;&gt;&lt;div class=&quot;embed-loading&quot;&gt;&lt;div class=&quot;loadingRow&quot;&gt;&lt;/div&gt;&lt;div class=&quot;loadingRow&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;a class=&quot;embed-card&quot; href=&quot;https://x.com/kranirudha/status/1944689973610848316?s=20&quot;&gt;https://x.com/kranirudha/status/1944689973610848316?s=20&lt;/a&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://x.com/ShabnamBukhsh&quot; target=&quot;_blank&quot;&gt;Shabnam&lt;/a&gt; and I got the opportunity to celebrate our marriage anniversary in Paris. I am so grateful that we were able to do this; it was our dream come true. The more we explore, the more we are humbled and grateful for the opportunities we have and the privilege of seeing the world.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;alt&quot; class=&quot;image--center mx-auto&quot; src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1767376893188/237f6152-726c-4bb2-9901-63b3371676bd.jpeg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Coming back to India, and we were neck deep with PyCon India work, I was a part of the website team since we decided to implement the website in-house this year. There was a lot of work. I am so grateful for all the volunteers who made this happen. The event was such a success, and I was also speaking at PyCon India. It was wonderful to speak and conduct some really interactive open spaces. I was so happy with the design and so proud since Shabnam did a lot of designs, and they turned out so beautiful. The cherry on top was &lt;a href=&quot;https://www.linkedin.com/in/rajeev-shivah-49745014a/&quot; target=&quot;_blank&quot;&gt;Rajeev&lt;/a&gt; was attending PyCon for the first time. A small personal win has always been my college juniors attending PyCon, and a bunch of them were. I was so proud to see &lt;a href=&quot;https://www.linkedin.com/in/gagan-s-105706202/&quot; target=&quot;_blank&quot;&gt;Gagan&lt;/a&gt; contributing to the website team.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;alt&quot; class=&quot;image--center mx-auto&quot; src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1767377070873/1a2f8f91-d98b-496b-b315-5f94012d2220.jpeg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Every PyCon grounds me and makes me think that if &lt;a href=&quot;https://x.com/yudocaa&quot; target=&quot;_blank&quot;&gt;Sayan&lt;/a&gt; hadn’t introduced it to me, I don’t know where I would be. Most of the friends I have now, I have met through PyCon and Dgplug. I have learnt about communities and the importance of standing for people.&lt;/p&gt;
&lt;p&gt;I also got the opportunity to visit Thailand. Anirudha and I were presenting at PyCon Thailand; it was a really petite conference, and such warm people. This allowed us to explore Bangkok, and we were blown away by the 7-Eleven there. We explored a lot of Bangkok with Anirudha, and we had a lot of fun doing it. We took this opportunity to do a small getaway at Krabi with Sayan and Shilpi. I am glad we did that, it was so much fun to explore the islands around and the waters. Every frame of this trip was straight out of a beautiful dream; for me, it was like living a dream. We enjoyed amazing food and a lot of local delicacies. The vastness of the ocean prompted me to write some beautiful poems.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;alt&quot; class=&quot;image--center mx-auto&quot; src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1767377700077/85ed9021-c08d-44d6-b56f-6adf189d6657.jpeg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;alt&quot; class=&quot;image--center mx-auto&quot; src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1767378376251/e513690c-5ca4-43d0-9e8f-cd3ab5069b23.jpeg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The year ended with me attending Science Hack Day in Belgaum, where I hacked on drones with &lt;a href=&quot;https://github.com/SaptakS&quot; target=&quot;_blank&quot;&gt;Saptak&lt;/a&gt;. This was originally &lt;a href=&quot;https://x.com/jithinbp_&quot; target=&quot;_blank&quot;&gt;Jithin&lt;/a&gt;’s idea that we stole, and the feeling of getting this to completion was so exhilarating.&lt;/p&gt;
&lt;p&gt;We ended up playing a lot of Uno, which was so much fun.&lt;/p&gt;
&lt;p&gt;I really enjoy this event, and the love that Praveen sir shows is what keeps bringing me back.&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;alt&quot; class=&quot;image--center mx-auto&quot; src=&quot;https://cdn.hashnode.com/res/hashnode/image/upload/v1767377976692/91504643-417a-43bb-81e8-868fdb709f2a.jpeg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Although I have talked about the travels and the good things, there were a bunch of lows for me. I failed at a lot of things; writing blogs is one of them. I am struggling with fitness and keeping up with a consistent workout routine. I am also struggling to carve out time to learn new tech, but I am trying with each day. I am trying to be a little bit better.&lt;/p&gt;
&lt;p&gt;Things I wanted to do this year:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Consistent workout&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Write more blogs&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Read more books&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Learn to manage my time better.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Travel more and see new cultures&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Eat clean and get rid of bad habits&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Meditate consistently&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Learn more about finance&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build and write projects&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Help more people&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Consistently journal my thoughts&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
	<pubDate>Fri, 02 Jan 2026 18:45:37 +0000</pubDate>
        <enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1767379380556/6f8b58aa-bc92-49e6-8457-917e6c89602d.jpeg" length="0" type="image/jpeg"/>
</item>
<item>
	<title>Priyanka Saggu: Is Kubernetes ServiceAccount a JWT token? And how to verify it?</title>
	<guid isPermaLink="true">https://psaggu.com/2025/12/19/k8s-serviceaccount-jwt.html</guid>
	<link>https://psaggu.com/2025/12/19/k8s-serviceaccount-jwt.html</link>
	<description>&lt;p&gt;&lt;em&gt;(More of my “notes for self”, as I continue reading the thesis paper, &lt;a href=&quot;https://github.com/luxas/research/blob/main/msc_thesis.pdf&quot;&gt;Usable Access Control in Cloud Management Systems&lt;/a&gt;, written by Lucas Käldström.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I ran another small experiment today.&lt;/p&gt;

&lt;p&gt;Today, I learnt that the Kubernetes Service Account tokens that I use very often to authenticate with the API server (using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Authorization: Bearer &amp;lt;token&amp;gt;&lt;/code&gt; header with the HTTP request) are JWT (JSON Web Token) tokens.&lt;/p&gt;

&lt;p&gt;I learnt this as a verbal fact first, so, I wanted to verify it in my mighty Kind cluster.&lt;/p&gt;

&lt;p&gt;So, let’s first create a Kind cluster.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ kind create cluster
Creating cluster &lt;span class=&quot;s2&quot;&gt;&quot;kind&quot;&lt;/span&gt; ...
 ✓ Ensuring node image &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;kindest/node:v1.34.0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 🖼
 ✓ Preparing nodes 📦  
 ✓ Writing configuration 📜 
 ✓ Starting control-plane 🕹️ 
 ✓ Installing CNI 🔌 
 ✓ Installing StorageClass 💾 
Set kubectl context to &lt;span class=&quot;s2&quot;&gt;&quot;kind-kind&quot;&lt;/span&gt;
You can now use your cluster with:

kubectl cluster-info &lt;span class=&quot;nt&quot;&gt;--context&lt;/span&gt; kind-kind

Thanks &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;using kind! 😊
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Create a test pod and exec inside the container.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ kubectl run jwt-test &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;--image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;busybox &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;--restart&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;Never &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sleep &lt;/span&gt;3600
pod/jwt-test created

❯ kubectl &lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-it&lt;/span&gt; jwt-test &lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; sh
/ &lt;span class=&quot;c&quot;&gt;# &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, I’m inside our container, let’s run some tests.&lt;/p&gt;

&lt;p&gt;First, print the contents of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/run/secrets/kubernetes.io/serviceaccount/token&lt;/code&gt; file.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/ &lt;span class=&quot;c&quot;&gt;# cat /var/run/secrets/kubernetes.io/serviceaccount/token&lt;/span&gt;

eyJhbGciOiJSUzI1NiIsImtpZCI6IncwY3FpcXhvZGt1SFlGelNQa1FwenFMcmpoeEFkVi1McjFYcTZVTEh3X1kifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzk3Njg0MTc3LCJpYXQiOjE3NjYxNDgxNzcsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwianRpIjoiMGQyMTFiNGEtNjVjMi00ODEyLWIwYjEtNGUzY2I2NzI5ZGMzIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0Iiwibm9kZSI6eyJuYW1lIjoia2luZC1jb250cm9sLXBsYW5lIiwidWlkIjoiNWU0MmM4M2YtMmI2NC00ZjU3LWEyZGMtMjI3M2ZmZjk3ZTBlIn0sInBvZCI6eyJuYW1lIjoiand0LXRlc3QiLCJ1aWQiOiJlNDdmMDVlZi00MWMzLTRmNDctYTdmNC01MDc1ZmIzZGQ2ZDMifSwic2VydmljZWFjY291bnQiOnsibmFtZSI6ImRlZmF1bHQiLCJ1aWQiOiI4Y2ZhNWYxNS0wOWJhLTRmM2QtODE2Ny02OGFhNjE5ZjRmN2YifSwid2FybmFmdGVyIjoxNzY2MTUxNzg0fSwibmJmIjoxNzY2MTQ4MTc3LCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpkZWZhdWx0In0.PA010UKl5ldQCOAk5s-iNRHEsbxkyIscTUsNn1c3hE9TL-uTCTl7_7QnI8-NOmx5Qjj7GPvF2QaHCeynOXlLq-Nt5mcvnOb6IipTfcH0Mfa7OCBufgPo82ggUA7T09kwcs7pmxZoL_lHxBBElFOMl9cMyhYO7I46JZ_AmvmzO4ctD3_ojQ6cyciXx4YZt78IwbM9QdM24e64BjyI_rdCGk3Y8990zodydn447VP9V6UAVQJJV49eleUnWMnQHTc3Z8UGjmawLeSaDQTqxXQ_fr9YTpHwbA_MqmXggFAmVIVQo0hTjfZxtcxuJe-8mM69Lm9krNJ7PsEuQeUB_9WyxA
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;base64&lt;/code&gt; decode the above token I got.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;eyJhbGciOiJSUzI1NiIsImtpZCI6IncwY3FpcXhvZGt1SFlGelNQa1FwenFMcmpoeEFkVi1McjFYcTZVTEh3X1kifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzk3Njg0MTc3LCJpYXQiOjE3NjYxNDgxNzcsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwianRpIjoiMGQyMTFiNGEtNjVjMi00ODEyLWIwYjEtNGUzY2I2NzI5ZGMzIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0Iiwibm9kZSI6eyJuYW1lIjoia2luZC1jb250cm9sLXBsYW5lIiwidWlkIjoiNWU0MmM4M2YtMmI2NC00ZjU3LWEyZGMtMjI3M2ZmZjk3ZTBlIn0sInBvZCI6eyJuYW1lIjoiand0LXRlc3QiLCJ1aWQiOiJlNDdmMDVlZi00MWMzLTRmNDctYTdmNC01MDc1ZmIzZGQ2ZDMifSwic2VydmljZWFjY291bnQiOnsibmFtZSI6ImRlZmF1bHQiLCJ1aWQiOiI4Y2ZhNWYxNS0wOWJhLTRmM2QtODE2Ny02OGFhNjE5ZjRmN2YifSwid2FybmFmdGVyIjoxNzY2MTUxNzg0fSwibmJmIjoxNzY2MTQ4MTc3LCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpkZWZhdWx0In0.PA010UKl5ldQCOAk5s-iNRHEsbxkyIscTUsNn1c3hE9TL-uTCTl7_7QnI8-NOmx5Qjj7GPvF2QaHCeynOXlLq-Nt5mcvnOb6IipTfcH0Mfa7OCBufgPo82ggUA7T09kwcs7pmxZoL_lHxBBElFOMl9cMyhYO7I46JZ_AmvmzO4ctD3_ojQ6cyciXx4YZt78IwbM9QdM24e64BjyI_rdCGk3Y8990zodydn447VP9V6UAVQJJV49eleUnWMnQHTc3Z8UGjmawLeSaDQTqxXQ_fr9YTpHwbA_MqmXggFAmVIVQo0hTjfZxtcxuJe-8mM69Lm9krNJ7PsEuQeUB_9WyxA&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;base64&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;alg&quot;&lt;/span&gt;:&lt;span class=&quot;s2&quot;&gt;&quot;RS256&quot;&lt;/span&gt;,&lt;span class=&quot;s2&quot;&gt;&quot;kid&quot;&lt;/span&gt;:&lt;span class=&quot;s2&quot;&gt;&quot;w0cqiqxodkuHYFzSPkQpzqLrjhxAdV-Lr1Xq6ULHw_Y&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;base64&lt;/span&gt;: invalid input
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ah, I got an invalid input.&lt;/p&gt;

&lt;p&gt;But what I learnt is that a JWT token is a three part thing.&lt;br /&gt;
Each part is a Base64 encoded blob, separated (or joined by a dot).&lt;br /&gt;
So, a full token will look something like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;base64url(header)&amp;gt;.&amp;lt;base64url(payload)&amp;gt;.&amp;lt;base64url(signature)&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What happened in our first attempt at decoding the ServiceAccount token is -&lt;br /&gt;
it just decoded the first blob and then reached a dot, and failed there.&lt;/p&gt;

&lt;p&gt;So, if I divide the above token into 3 parts now, it will be:&lt;/p&gt;

&lt;p&gt;Part 1:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;eyJhbGciOiJSUzI1NiIsImtpZCI6IncwY3FpcXhvZGt1SFlGelNQa1FwenFMcmpoeEFkVi1McjFYcTZVTEh3X1kifQ
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Part 2:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzk3Njg0MTc3LCJpYXQiOjE3NjYxNDgxNzcsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwianRpIjoiMGQyMTFiNGEtNjVjMi00ODEyLWIwYjEtNGUzY2I2NzI5ZGMzIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0Iiwibm9kZSI6eyJuYW1lIjoia2luZC1jb250cm9sLXBsYW5lIiwidWlkIjoiNWU0MmM4M2YtMmI2NC00ZjU3LWEyZGMtMjI3M2ZmZjk3ZTBlIn0sInBvZCI6eyJuYW1lIjoiand0LXRlc3QiLCJ1aWQiOiJlNDdmMDVlZi00MWMzLTRmNDctYTdmNC01MDc1ZmIzZGQ2ZDMifSwic2VydmljZWFjY291bnQiOnsibmFtZSI6ImRlZmF1bHQiLCJ1aWQiOiI4Y2ZhNWYxNS0wOWJhLTRmM2QtODE2Ny02OGFhNjE5ZjRmN2YifSwid2FybmFmdGVyIjoxNzY2MTUxNzg0fSwibmJmIjoxNzY2MTQ4MTc3LCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpkZWZhdWx0In0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Part 3:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;PA010UKl5ldQCOAk5s-iNRHEsbxkyIscTUsNn1c3hE9TL-uTCTl7_7QnI8-NOmx5Qjj7GPvF2QaHCeynOXlLq-Nt5mcvnOb6IipTfcH0Mfa7OCBufgPo82ggUA7T09kwcs7pmxZoL_lHxBBElFOMl9cMyhYO7I46JZ_AmvmzO4ctD3_ojQ6cyciXx4YZt78IwbM9QdM24e64BjyI_rdCGk3Y8990zodydn447VP9V6UAVQJJV49eleUnWMnQHTc3Z8UGjmawLeSaDQTqxXQ_fr9YTpHwbA_MqmXggFAmVIVQo0hTjfZxtcxuJe-8mM69Lm9krNJ7PsEuQeUB_9WyxA
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;ok-now-lets-decode-them-one-by-one-again&quot;&gt;Ok, now let’s decode them one by one again!&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Decode Part 1:&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;eyJhbGciOiJSUzI1NiIsImtpZCI6IncwY3FpcXhvZGt1SFlGelNQa1FwenFMcmpoeEFkVi1McjFYcTZVTEh3X1kifQ&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;base64&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; | jq &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;alg&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;RS256&quot;&lt;/span&gt;,
  &lt;span class=&quot;s2&quot;&gt;&quot;kid&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;w0cqiqxodkuHYFzSPkQpzqLrjhxAdV-Lr1Xq6ULHw_Y&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The first key-value pair &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;alg&quot;: &quot;RS256&quot;&lt;/code&gt; in the output tells us, that this JWT token (which I will get in the next Part 2 decoding) was signed using a RS256 (RSA + SHA-256) algorithm.&lt;br /&gt;
So, if I need to verify the token signature, I know what is the algorithm used to sign it.&lt;/p&gt;

&lt;p&gt;And the second key-value pair, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;kid&quot;: &quot;w0cqiqxodkuHYFzSPkQpzqLrjhxAdV-Lr1Xq6ULHw_Y&quot;&lt;/code&gt; part.&lt;br /&gt;
This is a hint to figure out which RS256 (RSA + SHA-256) private/pubic key pair was actually used to sign.&lt;br /&gt;
The value I see in front of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kid&lt;/code&gt; is going to help us to figure out the public key of this pair.&lt;/p&gt;

&lt;p&gt;But where to find the Public Key? That information, I will get in the next part.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Decode Part 2:&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzk3Njg0MTc3LCJpYXQiOjE3NjYxNDgxNzcsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwianRpIjoiMGQyMTFiNGEtNjVjMi00ODEyLWIwYjEtNGUzY2I2NzI5ZGMzIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0Iiwibm9kZSI6eyJuYW1lIjoia2luZC1jb250cm9sLXBsYW5lIiwidWlkIjoiNWU0MmM4M2YtMmI2NC00ZjU3LWEyZGMtMjI3M2ZmZjk3ZTBlIn0sInBvZCI6eyJuYW1lIjoiand0LXRlc3QiLCJ1aWQiOiJlNDdmMDVlZi00MWMzLTRmNDctYTdmNC01MDc1ZmIzZGQ2ZDMifSwic2VydmljZWFjY291bnQiOnsibmFtZSI6ImRlZmF1bHQiLCJ1aWQiOiI4Y2ZhNWYxNS0wOWJhLTRmM2QtODE2Ny02OGFhNjE5ZjRmN2YifSwid2FybmFmdGVyIjoxNzY2MTUxNzg0fSwibmJmIjoxNzY2MTQ4MTc3LCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpkZWZhdWx0In0&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;base64&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; | jq &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;aud&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;https://kubernetes.default.svc.cluster.local&quot;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;,
  &lt;span class=&quot;s2&quot;&gt;&quot;exp&quot;&lt;/span&gt;: 1797684177,
  &lt;span class=&quot;s2&quot;&gt;&quot;iat&quot;&lt;/span&gt;: 1766148177,
  &lt;span class=&quot;s2&quot;&gt;&quot;iss&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;https://kubernetes.default.svc.cluster.local&quot;&lt;/span&gt;,
  &lt;span class=&quot;s2&quot;&gt;&quot;jti&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;0d211b4a-65c2-4812-b0b1-4e3cb6729dc3&quot;&lt;/span&gt;,
  &lt;span class=&quot;s2&quot;&gt;&quot;kubernetes.io&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;namespace&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;default&quot;&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;node&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;kind-control-plane&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;uid&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;5e42c83f-2b64-4f57-a2dc-2273fff97e0e&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;pod&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;jwt-test&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;uid&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;e47f05ef-41c3-4f47-a7f4-5075fb3dd6d3&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;serviceaccount&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;default&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;uid&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;8cfa5f15-09ba-4f3d-8167-68aa619f4f7f&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;warnafter&quot;&lt;/span&gt;: 1766151784
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
  &lt;span class=&quot;s2&quot;&gt;&quot;nbf&quot;&lt;/span&gt;: 1766148177,
  &lt;span class=&quot;s2&quot;&gt;&quot;sub&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;system:serviceaccount:default:default&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ok, this is the JWT token.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;iss&quot;: &quot;https://kubernetes.default.svc.cluster.local&quot;&lt;/code&gt; is what issued this JWT token. So, it’s the Issuer.&lt;/p&gt;

    &lt;p&gt;This is what I will use (later) to figure out the location of the public key.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;aud&quot;: [&quot;https://kubernetes.default.svc.cluster.local&quot;]&lt;/code&gt; tells us that who is the intended audience for this token.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;sub&quot;: &quot;system:serviceaccount:default:default&quot;&lt;/code&gt; tells us who is the subject of this token.&lt;/p&gt;

    &lt;p&gt;As in this token represents this service account (called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;default&lt;/code&gt; in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;default&lt;/code&gt; namespace).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;iat&quot;: 1766148177&lt;/code&gt; part stands for Issued-at, and so the value is a timestamp for when this token was issued (in unix format).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;nbf&quot;: 1766148177&lt;/code&gt; part stands for “not before” meaning this token can’t be used before this time.&lt;/p&gt;

    &lt;p&gt;In this example, it is matching the “Issued-at” time, but I’m assuming it can be configured (I don’t know how at this point).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;exp&quot;: 1797684177,&lt;/code&gt; part stands for “Expiration”, basically again it is a timestamp for when this token will expire.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;jti&quot;: &quot;0d211b4a-65c2-4812-b0b1-4e3cb6729dc3&quot;&lt;/code&gt; is a unique ID for this JWT token.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;And then the following part is a Kubernetes-specific entity, not really a standard JWT token field.&lt;/p&gt;

    &lt;p&gt;In this case, it’s giving Kubernetes some metadata information, for which namespace, and which particular instances of node, pod, etc are tied to this ServiceAccount.&lt;/p&gt;

    &lt;p&gt;And the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;warnafter&lt;/code&gt; bit tells when to automatically rotate this token.&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;s2&quot;&gt;&quot;kubernetes.io&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;namespace&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;default&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;node&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;kind-control-plane&quot;&lt;/span&gt;,
        &lt;span class=&quot;s2&quot;&gt;&quot;uid&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;5e42c83f-2b64-4f57-a2dc-2273fff97e0e&quot;&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;pod&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;jwt-test&quot;&lt;/span&gt;,
        &lt;span class=&quot;s2&quot;&gt;&quot;uid&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;e47f05ef-41c3-4f47-a7f4-5075fb3dd6d3&quot;&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;serviceaccount&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;default&quot;&lt;/span&gt;,
        &lt;span class=&quot;s2&quot;&gt;&quot;uid&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;8cfa5f15-09ba-4f3d-8167-68aa619f4f7f&quot;&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;warnafter&quot;&lt;/span&gt;: 1766151784
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;And finally, the Part 3 now:&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;PA010UKl5ldQCOAk5s-iNRHEsbxkyIscTUsNn1c3hE9TL-uTCTl7_7QnI8-NOmx5Qjj7GPvF2QaHCeynOXlLq-Nt5mcvnOb6IipTfcH0Mfa7OCBufgPo82ggUA7T09kwcs7pmxZoL_lHxBBElFOMl9cMyhYO7I46JZ_AmvmzO4ctD3_ojQ6cyciXx4YZt78IwbM9QdM24e64BjyI_rdCGk3Y8990zodydn447VP9V6UAVQJJV49eleUnWMnQHTc3Z8UGjmawLeSaDQTqxXQ_fr9YTpHwbA_MqmXggFAmVIVQo0hTjfZxtcxuJe-8mM69Lm9krNJ7PsEuQeUB_9WyxA&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;base64&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;
5�B��W�&lt;span class=&quot;nv&quot;&gt;$�&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;base64&lt;/span&gt;: invalid input
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I got some some random binary code here.&lt;/p&gt;

&lt;p&gt;This I learnt is a raw RSA signature, that is used to sign the first 2 parts (Header and Payload) of the token.&lt;/p&gt;

&lt;p&gt;I learnt it’s something like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;RSA-SIGN(
  SHA256(
    base64url(header) + &quot;.&quot; + base64url(payload)
  )
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;where-to-find-the-public-key-used-to-sign-the-jwt-token&quot;&gt;where to find the Public key (used to sign the JWT token)?&lt;/h3&gt;

&lt;p&gt;I saw in Part 2 decoded output this entry about who issued the token.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;iss&quot;: &quot;https://kubernetes.default.svc.cluster.local&quot;,
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s see if I can find out some information from this Issuer url.&lt;/p&gt;

&lt;p&gt;But one thing to note, before I make any request.&lt;/p&gt;

&lt;p&gt;The Issuer of a JWT token stores the information that I am looking for at a path:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;https://&amp;lt;url-of-the-issuer&amp;gt;/.well-known/openid-configuration
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, back to our pod container.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ kubectl &lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-it&lt;/span&gt; jwt-test &lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; sh
/ &lt;span class=&quot;c&quot;&gt;# wget https://kubernetes.default.svc.cluster.local&lt;/span&gt;
Connecting to kubernetes.default.svc.cluster.local &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;10.96.0.1:443&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
wget: note: TLS certificate validation not implemented
wget: server returned error: HTTP/1.1 403 Forbidden
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;ok, when I tried to hit the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://kubernetes.default.svc.cluster.local&lt;/code&gt; url, I got &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;403 Forbidden&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, I need some credentials.&lt;/p&gt;

&lt;p&gt;You know what, here is what the Service Account token is used for.&lt;/p&gt;

&lt;p&gt;I will pass the token as a Autherization header in our request.&lt;/p&gt;

&lt;p&gt;Let’s try again.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/ &lt;span class=&quot;c&quot;&gt;# TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)&lt;/span&gt;

/ &lt;span class=&quot;c&quot;&gt;# wget --header=&quot;Authorization: Bearer $TOKEN&quot; https://kubernetes.default.svc.cluster.local/.well-known/openid-configuration --no-check-certificate&lt;/span&gt;

Connecting to kubernetes.default.svc.cluster.local &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;10.96.0.1:443&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
saving to &lt;span class=&quot;s1&quot;&gt;'openid-configuration'&lt;/span&gt;
openid-configuration 100% |&lt;span class=&quot;k&quot;&gt;********************************************************************************************&lt;/span&gt;|   236  0:00:00 ETA
&lt;span class=&quot;s1&quot;&gt;'openid-configuration'&lt;/span&gt; saved

/ &lt;span class=&quot;c&quot;&gt;# cat openid-configuration | jq .&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;issuer&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;https://kubernetes.default.svc.cluster.local&quot;&lt;/span&gt;,
  &lt;span class=&quot;s2&quot;&gt;&quot;jwks_uri&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;https://172.20.0.2:6443/openid/v1/jwks&quot;&lt;/span&gt;,
  &lt;span class=&quot;s2&quot;&gt;&quot;response_types_supported&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;id_token&quot;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;,
  &lt;span class=&quot;s2&quot;&gt;&quot;subject_types_supported&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;public&quot;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;,
  &lt;span class=&quot;s2&quot;&gt;&quot;id_token_signing_alg_values_supported&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;RS256&quot;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ok, look at this part - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;jwks_uri&quot;: &quot;https://172.20.0.2:6443/openid/v1/jwks&quot;&lt;/code&gt;.&lt;br /&gt;
The “jwks” in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jwks_url&lt;/code&gt; stands for “JSON Web Key Set”.&lt;br /&gt;
This is what holds a collection of cryptographic public keys, used primarily for verifying digital signatures on JWT tokens.&lt;/p&gt;

&lt;p&gt;So, I have almost gotten what I need.&lt;br /&gt;
Let’s hit this JWKS URL now.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/ &lt;span class=&quot;c&quot;&gt;# wget --header=&quot;Authorization: Bearer $TOKEN&quot; https://172.20.0.2:6443/openid/v1/jwks --no-check-certificate&lt;/span&gt;
Connecting to 172.20.0.2:6443 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;172.20.0.2:6443&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
saving to &lt;span class=&quot;s1&quot;&gt;'jwks'&lt;/span&gt;
jwks                 100% |&lt;span class=&quot;k&quot;&gt;********************************************************************************************&lt;/span&gt;|   462  0:00:00 ETA
&lt;span class=&quot;s1&quot;&gt;'jwks'&lt;/span&gt; saved

/# &lt;span class=&quot;nb&quot;&gt;cat &lt;/span&gt;jwks | jq &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;keys&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;use&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;sig&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;kty&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;RSA&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;kid&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;w0cqiqxodkuHYFzSPkQpzqLrjhxAdV-Lr1Xq6ULHw_Y&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;alg&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;RS256&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;n&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;vKsQjvpHQWbez2dLiTb2aJp36SKpVWvk-egE1pRertMJmtq3eeDPskb8n_msAWY4GKIMx3RnmfKBMbs_WHAkVt681cH0AzF5CR_oUtJ0Unde1rInUls5nxQcQ7_cCjApyKQlY5x5Z_vASyh7fOvMKUWmfLJt7M20hDoEvlM0WF9kUeqAgexBXlFv106qc-3CoO2-HPN6mlOn8WqHd-Ky_jQaj5xm__A0o04H7JEu09n7_Z9Rws9TFqBHaGCXwio3cozh2Bjv6da7rmyZUSp7ztH_4UcfYQgt5iJnxUdsjD7vXnyWFwvefs-6Wn6vlRp4fVmCfNrkzDL7QPWsjJJoWQ&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;e&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;AQAB&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Voila, I got it.&lt;/p&gt;

&lt;p&gt;See, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kid&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alg&lt;/code&gt; matches exactly what I got in the decoded output of Part 1 of the JWT token.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;alg&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;RS256&quot;&lt;/span&gt;,
  &lt;span class=&quot;s2&quot;&gt;&quot;kid&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;w0cqiqxodkuHYFzSPkQpzqLrjhxAdV-Lr1Xq6ULHw_Y&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So, I think the last part left for us now is to understand how can i use this to verify the signature now on the token?&lt;/p&gt;

&lt;h3 id=&quot;lets-verify-the-token&quot;&gt;let’s verify the token!&lt;/h3&gt;

&lt;p&gt;So, to verify the token. I will need the following bit I got from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jwks_uri&lt;/code&gt; output.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s2&quot;&gt;&quot;n&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;vKsQjvpHQWbez2dLiTb2aJp36SKpVWvk-egE1pRertMJmtq3eeDPskb8n_msAWY4GKIMx3RnmfKBMbs_WHAkVt681cH0AzF5CR_oUtJ0Unde1rInUls5nxQcQ7_cCjApyKQlY5x5Z_vASyh7fOvMKUWmfLJt7M20hDoEvlM0WF9kUeqAgexBXlFv106qc-3CoO2-HPN6mlOn8WqHd-Ky_jQaj5xm__A0o04H7JEu09n7_Z9Rws9TFqBHaGCXwio3cozh2Bjv6da7rmyZUSp7ztH_4UcfYQgt5iJnxUdsjD7vXnyWFwvefs-6Wn6vlRp4fVmCfNrkzDL7QPWsjJJoWQ&quot;&lt;/span&gt;,
&lt;span class=&quot;s2&quot;&gt;&quot;e&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;AQAB&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note: all notes this point onwards is me copy/pasting instructions I got from docs or otherwise tinkering with AI.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e&lt;/code&gt; are respectively called the “modulus” and “public exponent” which is what I will use to contruct the RSA public key.&lt;/p&gt;

&lt;p&gt;Below mathematics is what is used to convert the “n” and “e” to a public key.&lt;/p&gt;

&lt;p&gt;What the following process does is 5 things for the “n” and “e” values I got:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;convert them from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;base64url&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;base64&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;binary&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;then interpret them as Integers&lt;/li&gt;
  &lt;li&gt;then wrap them into something called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ASN.1&lt;/code&gt; structure&lt;/li&gt;
  &lt;li&gt;then do something called DER (Distinguished Encoding Rules) encoding this above &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ASN.1&lt;/code&gt; structure&lt;/li&gt;
  &lt;li&gt;and finall wrap that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DER&lt;/code&gt; into a PEM.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once I got the PEM version, at that point, openssl will be able to use it.&lt;/p&gt;

&lt;p&gt;I’m doing the below steps on my host machine, because i need &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openssl&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;base64&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xxd&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jq&lt;/code&gt;, which are not present in the container.&lt;/p&gt;

&lt;p&gt;Ok, first step - we decode &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e&lt;/code&gt; to binary, replacing the following and adding padding (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=&lt;/code&gt;):&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ &lt;span class=&quot;nv&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;vKsQjvpHQWbez2dLiTb2aJp36SKpVWvk-egE1pRertMJmtq3eeDPskb8n_msAWY4GKIMx3RnmfKBMbs_WHAkVt681cH0AzF5CR_oUtJ0Unde1rInUls5nxQcQ7_cCjApyKQlY5x5Z_vASyh7fOvMKUWmfLJt7M20hDoEvlM0WF9kUeqAgexBXlFv106qc-3CoO2-HPN6mlOn8WqHd-Ky_jQaj5xm__A0o04H7JEu09n7_Z9Rws9TFqBHaGCXwio3cozh2Bjv6da7rmyZUSp7ztH_4UcfYQgt5iJnxUdsjD7vXnyWFwvefs-6Wn6vlRp4fVmCfNrkzDL7QPWsjJJoWQ&quot;&lt;/span&gt;

❯ &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$n&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'_-'&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/+'&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;base64&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; n.bin

❯ &lt;span class=&quot;nv&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;AQAB&quot;&lt;/span&gt;

❯ &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$e&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;base64&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; e.bin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;ok, now do:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ xxd e.bin
00000000: 0100 01                                  ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This represents the number &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;65537&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, we need to convert these 2 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n.bin&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e.bin&lt;/code&gt; binaries to Hexadecimal strings.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ xxd &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; n.bin | &lt;span class=&quot;nb&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'\n'&lt;/span&gt;
bcab108efa474166decf674b8936f6689a77e922a9556be4f9e804d6945eaed3099adab779e0cfb246fc9ff9ac01663818a20cc7746799f28131bb3f58702456debcd5c1f4033179091fe852d27452775ed6b227525b399f141c43bfdc0a3029c8a425639c7967fbc04b287b7cebcc2945a67cb26deccdb4843a04be5334585f6451ea8081ec415e516fd74eaa73edc2a0edbe1cf37a9a53a7f16a8777e2b2fe341a8f9c66fff034a34e07ec912ed3d9fbfd9f51c2cf5316a047686097c22a37728ce1d818efe9d6bbae6c99512a7bced1ffe1471f61082de62267c5476c8c3eef5e7c96170bde7ecfba5a7eaf951a787d59827cdae4cc32fb40f5ac8c926859

❯ xxd &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; e.bin
010001
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, we need to convert these into an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ASN.1&lt;/code&gt; format.&lt;/p&gt;

&lt;p&gt;so, we create a file called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rsa.asn1&lt;/code&gt;, with the following contents:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;asn1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;SEQUENCE:rsa_key

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;rsa_key]
&lt;span class=&quot;nv&quot;&gt;modulus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;INTEGER:0x&amp;lt;PASTE_HEX_OF_N_HERE&amp;gt;
&lt;span class=&quot;nv&quot;&gt;publicExponent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;INTEGER:0x&amp;lt;PASTE_HEX_OF_E_HERE&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;so, the final version would look something like:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ &lt;span class=&quot;nb&quot;&gt;cat &lt;/span&gt;rsa.asn1 
&lt;span class=&quot;nv&quot;&gt;asn1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;SEQUENCE:rsa_key

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;rsa_key]
&lt;span class=&quot;nv&quot;&gt;modulus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;INTEGER:0xbcab108efa474166decf674b8936f6689a77e922a9556be4f9e804d6945eaed3099adab779e0cfb246fc9ff9ac01663818a20cc7746799f28131bb3f58702456debcd5c1f4033179091fe852d27452775ed6b227525b399f141c43bfdc0a3029c8a425639c7967fbc04b287b7cebcc2945a67cb26deccdb4843a04be5334585f6451ea8081ec415e516fd74eaa73edc2a0edbe1cf37a9a53a7f16a8777e2b2fe341a8f9c66fff034a34e07ec912ed3d9fbfd9f51c2cf5316a047686097c22a37728ce1d818efe9d6bbae6c99512a7bced1ffe1471f61082de62267c5476c8c3eef5e7c96170bde7ecfba5a7eaf951a787d59827cdae4cc32fb40f5ac8c926859
&lt;span class=&quot;nv&quot;&gt;publicExponent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;INTEGER:0x010001
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ASN.1&lt;/code&gt; format available now, we can generate a DER encoded value.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ openssl asn1parse &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;-genconf&lt;/span&gt; rsa.asn1 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;-out&lt;/span&gt; rsa_pub.der
   
    0:d&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0  &lt;span class=&quot;nv&quot;&gt;hl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;4 &lt;span class=&quot;nv&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 266 cons: SEQUENCE          
    4:d&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1  &lt;span class=&quot;nv&quot;&gt;hl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;4 &lt;span class=&quot;nv&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 257 prim: INTEGER           :BCAB108EFA474166DECF674B8936F6689A77E922A9556BE4F9E804D6945EAED3099ADAB779E0CFB246FC9FF9AC01663818A20CC7746799F28131BB3F58702456DEBCD5C1F4033179091FE852D27452775ED6B227525B399F141C43BFDC0A3029C8A425639C7967FBC04B287B7CEBCC2945A67CB26DECCDB4843A04BE5334585F6451EA8081EC415E516FD74EAA73EDC2A0EDBE1CF37A9A53A7F16A8777E2B2FE341A8F9C66FFF034A34E07EC912ED3D9FBFD9F51C2CF5316A047686097C22A37728CE1D818EFE9D6BBAE6C99512A7BCED1FFE1471F61082DE62267C5476C8C3EEF5E7C96170BDE7ECFBA5A7EAF951A787D59827CDAE4CC32FB40F5AC8C926859
  265:d&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1  &lt;span class=&quot;nv&quot;&gt;hl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;2 &lt;span class=&quot;nv&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;   3 prim: INTEGER           :010001
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Before we move ahead, I want to show why we are doing all this.&lt;/p&gt;

&lt;p&gt;Because, the RSA Public key will be of this structure:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;RSAPublicKey ::= SEQUENCE {
  modulus           INTEGER (n),
  publicExponent    INTEGER (e)
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;so, if you see the output of our DER encoding command, we see somethings that are needed in the above RSA Public Key structure.&lt;/p&gt;

&lt;p&gt;In the output, we have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SEQUENCE&lt;/code&gt; consisting of two prime INTEGERS.&lt;br /&gt;
That’s exactly what we need.&lt;/p&gt;

&lt;p&gt;Now, we are almost close to the final part, of actually converting the “n” and “e” to a RSA Public key.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ openssl rsa &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;-pubin&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;-inform&lt;/span&gt; DER &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;-in&lt;/span&gt; rsa_pub.der &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;-outform&lt;/span&gt; PEM &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;-out&lt;/span&gt; public.pem
writing RSA key

❯ &lt;span class=&quot;nb&quot;&gt;cat &lt;/span&gt;public.pem 
&lt;span class=&quot;nt&quot;&gt;-----BEGIN&lt;/span&gt; PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvKsQjvpHQWbez2dLiTb2
aJp36SKpVWvk+egE1pRertMJmtq3eeDPskb8n/msAWY4GKIMx3RnmfKBMbs/WHAk
Vt681cH0AzF5CR/oUtJ0Unde1rInUls5nxQcQ7/cCjApyKQlY5x5Z/vASyh7fOvM
KUWmfLJt7M20hDoEvlM0WF9kUeqAgexBXlFv106qc+3CoO2+HPN6mlOn8WqHd+Ky
/jQaj5xm//A0o04H7JEu09n7/Z9Rws9TFqBHaGCXwio3cozh2Bjv6da7rmyZUSp7
ztH/4UcfYQgt5iJnxUdsjD7vXnyWFwvefs+6Wn6vlRp4fVmCfNrkzDL7QPWsjJJo
WQIDAQAB
&lt;span class=&quot;nt&quot;&gt;-----END&lt;/span&gt; PUBLIC KEY-----
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Hurrah! Hurrah! Hurrah! We have the public key! finally!&lt;/p&gt;

&lt;p&gt;ok, but let’s verify once&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ openssl rsa &lt;span class=&quot;nt&quot;&gt;-pubin&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-in&lt;/span&gt; public.pem &lt;span class=&quot;nt&quot;&gt;-text&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-noout&lt;/span&gt;
Public-Key: &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;2048 bit&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Modulus:
    00:bc:ab:10:8e:fa:47:41:66:de:cf:67:4b:89:36:
    f6:68:9a:77:e9:22:a9:55:6b:e4:f9:e8:04:d6:94:
    5e:ae:d3:09:9a:da:b7:79:e0:cf:b2:46:fc:9f:f9:
    ac:01:66:38:18:a2:0c:c7:74:67:99:f2:81:31:bb:
    3f:58:70:24:56:de:bc:d5:c1:f4:03:31:79:09:1f:
    e8:52:d2:74:52:77:5e:d6:b2:27:52:5b:39:9f:14:
    1c:43:bf:dc:0a:30:29:c8:a4:25:63:9c:79:67:fb:
    c0:4b:28:7b:7c:eb:cc:29:45:a6:7c:b2:6d:ec:cd:
    b4:84:3a:04:be:53:34:58:5f:64:51:ea:80:81:ec:
    41:5e:51:6f:d7:4e:aa:73:ed:c2:a0:ed:be:1c:f3:
    7a:9a:53:a7:f1:6a:87:77:e2:b2:fe:34:1a:8f:9c:
    66:ff:f0:34:a3:4e:07:ec:91:2e:d3:d9:fb:fd:9f:
    51:c2:cf:53:16:a0:47:68:60:97:c2:2a:37:72:8c:
    e1:d8:18:ef:e9:d6:bb:ae:6c:99:51:2a:7b:ce:d1:
    ff:e1:47:1f:61:08:2d:e6:22:67:c5:47:6c:8c:3e:
    ef:5e:7c:96:17:0b:de:7e:cf:ba:5a:7e:af:95:1a:
    78:7d:59:82:7c:da:e4:cc:32:fb:40:f5:ac:8c:92:
    68:59
Exponent: 65537 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;0x10001&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;we-got-the-public-key-lets-verify-the-jwt-token-now&quot;&gt;We got the Public Key! Let’s verify the JWT token now.&lt;/h3&gt;

&lt;p&gt;Ok, I’m back to doing things by myself now.&lt;/p&gt;

&lt;p&gt;Remember from the Part 1 and Part 2 of the token were actually the “Header” and “Payload”. And “Part3”, the signature.&lt;/p&gt;

&lt;p&gt;What we have to verify is Part 1 and Part 2, which is what is signed by Part 3.&lt;/p&gt;

&lt;p&gt;So, let’s sort out the the required parts.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ &lt;span class=&quot;nv&quot;&gt;TOKEN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;eyJhbGciOiJSUzI1NiIsImtpZCI6IncwY3FpcXhvZGt1SFlGelNQa1FwenFMcmpoeEFkVi1McjFYcTZVTEh3X1kifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzk3Njg3ODgxLCJpYXQiOjE3NjYxNTE4ODEsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwianRpIjoiNmJiNzc0MjMtNmE3Yi00MjBmLTg1MDgtOTUzY2Y0YmE5MWZhIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0Iiwibm9kZSI6eyJuYW1lIjoia2luZC1jb250cm9sLXBsYW5lIiwidWlkIjoiNWU0MmM4M2YtMmI2NC00ZjU3LWEyZGMtMjI3M2ZmZjk3ZTBlIn0sInBvZCI6eyJuYW1lIjoiand0LXRlc3QiLCJ1aWQiOiI4M2E5YmE4OC0yOTg5LTRlYmItYTRiZS04ZjA0ODY2ZmM4OGEifSwic2VydmljZWFjY291bnQiOnsibmFtZSI6ImRlZmF1bHQiLCJ1aWQiOiI4Y2ZhNWYxNS0wOWJhLTRmM2QtODE2Ny02OGFhNjE5ZjRmN2YifSwid2FybmFmdGVyIjoxNzY2MTU1NDg4fSwibmJmIjoxNzY2MTUxODgxLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpkZWZhdWx0In0.ByKLRb2376aYeAmOWL1LTHsRmwgjWYp3kklUmoDcAzfMXWOBOcU_R4iXC4UqM5iwpEw_lWhDgEndGghiUg6HFau0rtj5VxFiFWwXkxSfzYNvxzW_nO3uFZlI4R3tWJqIeLMX3hqaWQGb_LvfvjI1My6XNZhkt8UTByUg3nKTmtMWmg-9-XKMylmD078vT4n8f0nSL6YlchJuTFivWc1lGE-FrZmWk6WeiRtH_jTyXp95dhg_Chf566otezUrPE8ern-8sI0rSVDzvLNsF4YvL9IXx2JQn57QR_Pr3otFXpeUTgj5oBUllsCTrA2xpXRmWxUD9qoncjviVkAkcj1fiw

❯ &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$TOKEN&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f1&lt;/span&gt;,2 &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; signed-data.txt

❯ &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$TOKEN&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f3&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'_-'&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/+'&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;base64&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; signature.bin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;ok, now, we verify the signed-data.txt with the signature.bin&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ openssl dgst &lt;span class=&quot;nt&quot;&gt;-sha256&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
∙   &lt;span class=&quot;nt&quot;&gt;-verify&lt;/span&gt; public.pem &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
∙   &lt;span class=&quot;nt&quot;&gt;-signature&lt;/span&gt; signature.bin &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
∙   signed-data.txt
Verification failure
40F7505CB27F0000:error:02000068:rsa routines:ossl_rsa_verify:bad signature:crypto/rsa/rsa_sign.c:442:
40F7505CB27F0000:error:1C880004:Provider routines:rsa_verify_directly:RSA lib:providers/implementations/signature/rsa_sig.c:1043:
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and I failed. 😂&lt;/p&gt;

&lt;p&gt;Goodness, the process was tiring, so, I’m not repeating it right now.&lt;/p&gt;

&lt;p&gt;I’ll come back to it and see at what place, I made mistakes.&lt;/p&gt;

&lt;p&gt;But this effort was to learn how it is done, i.e., how a signature verification happens.&lt;/p&gt;

&lt;p&gt;And also, I should not forget it all started with me just trying to understand whether a Kubernetes Service Account is a JWT token.&lt;/p&gt;

&lt;p&gt;I got my answer and I learnt so much more.&lt;/p&gt;

&lt;p&gt;There’s an article that I haven’t read just yet, but I was recommended to read (by &lt;a href=&quot;https://github.com/luxas&quot;&gt;Lucas Käldström&lt;/a&gt;).&lt;br /&gt;
Because, we didn’t end with a shiny green “verified” message, I will leave you to read that brilliant article - &lt;br /&gt;
&lt;a href=&quot;https://www.cs.cornell.edu/courses/cs5430/2015sp/notes/rsa_sign_vs_dec.php&quot;&gt;RSA Signing is Not RSA Decryption&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thank you, if you followed so far. :)&lt;/p&gt;</description>
	<pubDate>Fri, 19 Dec 2025 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Priyanka Saggu: Understanding kubeadm Bootstrap Tokens (through Node Bootstrapping)</title>
	<guid isPermaLink="true">https://psaggu.com/2025/12/15/kubeadm-bootstrap-token.html</guid>
	<link>https://psaggu.com/2025/12/15/kubeadm-bootstrap-token.html</link>
	<description>&lt;p&gt;&lt;em&gt;(This blog is basically a set of notes for self, as I read and try to understand the thesis paper, &lt;a href=&quot;https://github.com/luxas/research/blob/main/msc_thesis.pdf&quot;&gt;Usable Access Control in Cloud Management Systems&lt;/a&gt;, written by Lucas Käldström.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For a good while now, I have been wanting to understand how a node joins a Kubernetes cluster using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubeadm join&lt;/code&gt; command.&lt;br /&gt;
And especially, the part about the symmetric token (that we generate or we get from the control plane node after a successful &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubeadm init&lt;/code&gt; run, and then we share it with all other nodes wanting to join the cluster).&lt;/p&gt;

&lt;p&gt;So, things I want to understand are:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;why there’s a symmetric token?&lt;/li&gt;
  &lt;li&gt;and what is the role of this token?&lt;/li&gt;
  &lt;li&gt;and can I try to create a kubeadm token manually and use that to join an existing Kubernetes cluster successfully?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And as I read more and more of the thesis paper (linked at the top), I am understanding that the Access control mechanism(s) (for authentication, and authorization, and admission) used within the Kubernetes clusters are extremly elaborate and thought out from security perspective (and ofcourse, they’re not simple at all, not right away at least).&lt;br /&gt;
So, seeing a simple token passed through the command line in plain text format felt a bit off the place (or too simple right away).&lt;/p&gt;

&lt;p&gt;And ofcourse, I have a feeling, that it is not. So, following is me trying to figure out some answers for my questions.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;q-what-is-the-role-of-a-kubeadm-bootstrap-token&quot;&gt;Q: What is the role of a kubeadm bootstrap token?&lt;/h3&gt;

&lt;p&gt;I created a simple Kind cluster, and looked for anything “bootstrap” related on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kube-apiserver-*&lt;/code&gt; pod.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ kind create cluster

❯ kubectl get pod kube-apiserver-kind-control-plane &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; kube-system &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; yaml | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;bootstrap&quot;&lt;/span&gt;

   - &lt;span class=&quot;nt&quot;&gt;--enable-bootstrap-token-auth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I got a flag in the output, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--enable-bootstrap-token-auth=true&lt;/code&gt;.&lt;br /&gt;
And I don’t know what this flag actually does.&lt;/p&gt;

&lt;p&gt;Now, let’s create a simple docker container with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kube-apiserver&lt;/code&gt; image and look at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kube-apiserver --help&lt;/code&gt; menu to get the definition of the flag.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ kubectl get pod kube-apiserver-kind-control-plane &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; kube-system &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; yaml | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;image:&quot;&lt;/span&gt;
   image: registry.k8s.io/kube-apiserver:v1.34.0
   image: registry.k8s.io/kube-apiserver-amd64:v1.34.0

❯ docker run &lt;span class=&quot;nt&quot;&gt;-it&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--entrypoint&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt; registry.k8s.io/kube-apiserver:v1.34.0 kube-apiserver &lt;span class=&quot;nt&quot;&gt;--help&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;bootstrap&quot;&lt;/span&gt;

     &lt;span class=&quot;nt&quot;&gt;--enable-bootstrap-token-auth&lt;/span&gt;                       Enable to allow secrets of &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'bootstrap.kubernetes.io/token'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;the &lt;span class=&quot;s1&quot;&gt;'kube-system'&lt;/span&gt; namespace to be used &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;TLS bootstrapping authentication.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In simple words, how I understand it as:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;If I set the flag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--enable-bootstrap-token-auth&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;True&lt;/code&gt;, then the API server is configured to trust a list of (kubeadm) bootstrap tokens.&lt;/li&gt;
  &lt;li&gt;These tokens needs to be stored as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Secret&lt;/code&gt; object (of a very specific type - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bootstrap.kubernetes.io/token&lt;/code&gt;)  in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kube-system&lt;/code&gt; namespace.&lt;/li&gt;
  &lt;li&gt;and once that is done, then if a joining node (actually, the kubelet running on the joining node) makes a “TLS bootstrapping authentication” request using the “bootstrap token” in the request header (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Authorization: Bearer &amp;lt;token&amp;gt;&lt;/code&gt;), then the request will be authenticated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, we have some information now about the kubeadm bootstrap token.&lt;/p&gt;

&lt;p&gt;But you know what, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubeadm&lt;/code&gt; itself explains the role of the token much better:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ root@kind-control-plane:/# kubeadm token &lt;span class=&quot;nt&quot;&gt;--help&lt;/span&gt;

This &lt;span class=&quot;nb&quot;&gt;command &lt;/span&gt;manages bootstrap tokens. It is optional and needed only &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;advanced use cases.

In short, bootstrap tokens are used &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;establishing bidirectional trust between a client and a server.
A bootstrap token can be used when a client &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;example a node that is about to &lt;span class=&quot;nb&quot;&gt;join &lt;/span&gt;the cluster&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; needs
to trust the server it is talking to. Then a bootstrap token with the &lt;span class=&quot;s2&quot;&gt;&quot;signing&quot;&lt;/span&gt; usage can be used.
bootstrap tokens can also &lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;as a way to allow short-lived authentication to the API Server
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;the token serves as a way &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;the API Server to trust the client&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;example &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;doing the TLS Bootstrap.

What is a bootstrap token more exactly?
 - It is a Secret &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;the kube-system namespace of &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;bootstrap.kubernetes.io/token&quot;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
 - A bootstrap token must be of the form &lt;span class=&quot;s2&quot;&gt;&quot;[a-z0-9]{6}.[a-z0-9]{16}&quot;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; The former part is the public token ID,
   &lt;span class=&quot;k&quot;&gt;while &lt;/span&gt;the latter is the Token Secret and it must be kept private at all circumstances!
 - The name of the Secret must be named &lt;span class=&quot;s2&quot;&gt;&quot;bootstrap-token-(token-id)&quot;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;

You can &lt;span class=&quot;nb&quot;&gt;read &lt;/span&gt;more about bootstrap tokens here:
  https://kubernetes.io/docs/admin/bootstrap-tokens/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Also, the link at the bottom doesn’t work anymore.&lt;br /&gt;
Correct one (atleast as of writing) is - &lt;a href=&quot;https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-token/&quot;&gt;kubeadm token&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, at this point we have a verbal answer for the question - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;what is the role of the kubeadm token?&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, I want to try is to create a manual kubeadm token (and now, from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubeadm --help&lt;/code&gt; output, I also know what is the format of a valid kubeadm token).&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I am continuing on the Kind cluster we created above.&lt;/p&gt;

&lt;p&gt;The control-plane node (docker container) was created with the IP address - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;172.18.0.2&lt;/code&gt;.&lt;br /&gt;
(leaving it here as a note, because we will use it later. And this is the future me talking, I didn’t know it as I was trying things.)&lt;/p&gt;

&lt;p&gt;To simulate a new node, I didn’t use kind’s built-in multi-node support.&lt;br /&gt;
Instead, I created a plain docker container on the same network (the docker bridge network with the name, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kind&lt;/code&gt;):&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ docker run &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-it&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; joining-node &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--privileged&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--network&lt;/span&gt; kind &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  kindest/node:latest

❯ docker container ps
CONTAINER ID   IMAGE                  COMMAND                  CREATED             STATUS             PORTS                       NAMES
83ab08acf723   kindest/node:latest    &lt;span class=&quot;s2&quot;&gt;&quot;/usr/local/bin/entr…&quot;&lt;/span&gt;   7 seconds ago       Up 6 seconds                                   joining-node
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This new container has nothing but the basic tools installed (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubeadm&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubelet&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubectl&lt;/code&gt; and a clean filesystem, coming from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kindest/node&lt;/code&gt; image).&lt;br /&gt;
So, as of now, no certificates, no kubeconfig, nothing.&lt;/p&gt;

&lt;p&gt;Also note the name of the container, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;joining-node&lt;/code&gt;.&lt;br /&gt;
(I will use it later to exec inside the container and use it as a joining node).&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;q-can-i-create-a-kubeadm-token-manually-and-use-it-to-join-an-existing-kubernetes-cluster-successfully&quot;&gt;Q: Can I create a kubeadm token manually and use it to join an existing Kubernetes cluster successfully?&lt;/h3&gt;

&lt;p&gt;Back to the rules we got earlier:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;What is a bootstrap token more exactly?&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;It is a Secret in the kube-system namespace of type “bootstrap.kubernetes.io/token”.&lt;/li&gt;
    &lt;li&gt;A bootstrap token must be of the form “[a-z0-9]{6}.[a-z0-9]{16}”. The former part is the public token ID,
 while the latter is the Token Secret and it must be kept private at all circumstances!&lt;/li&gt;
    &lt;li&gt;The name of the Secret must be named “bootstrap-token-(token-id)”.&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;I am creating the following Secret object in the cluster (from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kind-control-plane&lt;/code&gt; node).&lt;br /&gt;
Notice the token bits I added in the yaml - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;token-id: pqrstu&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;token-secret: abcdef1234567890&lt;/code&gt;.&lt;br /&gt;
Together, these will give us the full token as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pqrstu.abcdef1234567890&lt;/code&gt;.&lt;br /&gt;
We will use this to make our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubeadm join&lt;/code&gt; requests.&lt;/p&gt;

&lt;p&gt;To come up with the following template, I referred to existing tokens from other multi-node Kind cluster.&lt;br /&gt;
(updated later: the template is also available here - &lt;a href=&quot;https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/#bootstrap-token-secret-format&quot;&gt;Bootstrap Token Secret Format&lt;/a&gt;)&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# bootstrap-token.yaml&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;apiVersion&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;v1&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Secret&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;bootstrap-token-pqrstu&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;kube-system&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;bootstrap.kubernetes.io/token&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;stringData&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;token-id&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;pqrstu&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;token-secret&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;abcdef1234567890&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;usage-bootstrap-authentication&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;true&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;usage-bootstrap-signing&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;true&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;expiration&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;2030-01-01T00:00:00Z&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Apply to create the token secret:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ kubectl apply &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; bootstrap-token.yaml

❯ kubectl get secrets &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; kube-system

NAME                     TYPE                            DATA   AGE
bootstrap-token-abcdef   bootstrap.kubernetes.io/token   6      58m
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now let’s make some first attempts to make the new docker container node (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;joining-node&lt;/code&gt;) join the Kind cluster.
(I have kept the verbosity of the logs very high).&lt;/p&gt;

&lt;p&gt;Inside the new node docker container, I started by running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubeadm join&lt;/code&gt; with no arguments:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ docker &lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-it&lt;/span&gt; joining-node /bin/bash

root@83ab08acf723:/# kubeadm &lt;span class=&quot;nb&quot;&gt;join&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--v&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;9

I1216 07:00:01.797859     164 join.go:423] &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;preflight] found NodeName empty&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; using OS &lt;span class=&quot;nb&quot;&gt;hostname &lt;/span&gt;as NodeName
I1216 07:00:01.798056     164 initconfiguration.go:122] detected and using CRI socket: unix:///var/run/containerd/containerd.sock
error: discovery: Invalid value: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;: bootstrapToken or file must be &lt;span class=&quot;nb&quot;&gt;set
&lt;/span&gt;no stack trace
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That failed immediately.&lt;/p&gt;

&lt;p&gt;Next, let’s try to give it the token we created above:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@83ab08acf723:/# kubeadm &lt;span class=&quot;nb&quot;&gt;join &lt;/span&gt;pqrstu.abcdef1234567890 &lt;span class=&quot;nt&quot;&gt;--v&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;9

error: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;discovery.bootstrapToken.caCertHashes: Invalid value: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;: using token-based discovery without caCertHashes can be unsafe. Set unsafeSkipCAVerification as &lt;span class=&quot;nb&quot;&gt;true &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;your kubeadm config file or pass &lt;span class=&quot;nt&quot;&gt;--discovery-token-unsafe-skip-ca-verification&lt;/span&gt; flag to &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;, discovery.bootstrapToken.token: Invalid value: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;: the bootstrap token is invalid, discovery.bootstrapToken.apiServerEndpoint: Invalid value: &lt;span class=&quot;s2&quot;&gt;&quot;pqrstu.abcdef1234567890&quot;&lt;/span&gt;: address pqrstu.abcdef1234567890: missing port &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;address, discovery.tlsBootstrapToken: Invalid value: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;: the bootstrap token is invalid]
no stack trace
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That produced a more informative error logs.&lt;br /&gt;
Now, we atleast know that kubeadm expects an endpoint to the API server first and then the token (maybe).&lt;/p&gt;

&lt;p&gt;Also the logs suggested us to pass &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--discovery-token-unsafe-skip-ca-verification&lt;/code&gt; flag to continue.&lt;br /&gt;
Let’s do that as well, to make some progress.&lt;/p&gt;

&lt;p&gt;(and yes, I could have already looked at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubeadm --help&lt;/code&gt; menu to understand the required format, but above test runs were intentional to understand basic flow).&lt;/p&gt;

&lt;p&gt;Ok, let’s provide everything properly that kubeadm actually needs:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@83ab08acf723:/# kubeadm &lt;span class=&quot;nb&quot;&gt;join &lt;/span&gt;172.18.0.2:6443 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--token&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;pqrstu.abcdef1234567890&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--discovery-token-unsafe-skip-ca-verification&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--v&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;9
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This time things moved some further.&lt;/p&gt;

&lt;p&gt;Let’s look at some important bits of the logs part by part.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;230 token.go:229] &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;discovery] Waiting &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;the cluster-info ConfigMap to receive a JWS signature &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;token ID &lt;span class=&quot;s2&quot;&gt;&quot;pqrstu&quot;&lt;/span&gt;
230 type.go:165] &lt;span class=&quot;s2&quot;&gt;&quot;Request Body&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;
230 round_trippers.go:527] &lt;span class=&quot;s2&quot;&gt;&quot;Request&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;curlCommand&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;lt;
	curl &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-XGET&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Accept: application/vnd.kubernetes.protobuf,application/json&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;User-Agent: kubeadm/v1.35.0 (linux/amd64) kubernetes/f35f950&quot;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://172.18.0.2:6443/api/v1/namespaces/kube-public/configmaps/cluster-info?timeout=10s'&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
230 round_trippers.go:562] &lt;span class=&quot;s2&quot;&gt;&quot;HTTP Trace: Dial succeed&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;network&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;tcp&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;172.18.0.2:6443&quot;&lt;/span&gt;
230 round_trippers.go:632] &lt;span class=&quot;s2&quot;&gt;&quot;Response&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;verb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;GET&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://172.18.0.2:6443/api/v1/namespaces/kube-public/configmaps/cluster-info?timeout=10s&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;200 OK&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;lt;...&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;From the above bits, it looks like at this point, we are able to successfully &lt;em&gt;&lt;strong&gt;authenticate&lt;/strong&gt;&lt;/em&gt; using the manually created token we passed (look at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;status=&quot;200 OK&quot;&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;But then after authentication, the API Server refused to let us continue further.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;230 round_trippers.go:527] &lt;span class=&quot;s2&quot;&gt;&quot;Request&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;curlCommand&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;lt;
	curl &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-XGET&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Accept: application/vnd.kubernetes.protobuf,application/json&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;User-Agent: kubeadm/v1.35.0 (linux/amd64) kubernetes/f35f950&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Authorization: Bearer &amp;lt;masked&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://kind-control-plane:6443/api/v1/namespaces/kube-system/configmaps/kubeadm-config?timeout=10s'&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;

230 round_trippers.go:632] &lt;span class=&quot;s2&quot;&gt;&quot;Response&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;verb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;GET&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://kind-control-plane:6443/api/v1/namespaces/kube-system/configmaps/kubeadm-config?timeout=10s&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;403 Forbidden&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;lt;...&amp;gt;

230 token.go:249] &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;discovery] Retrying due to error: could not find a JWS signature &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;the cluster-info ConfigMap &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;token ID &lt;span class=&quot;s2&quot;&gt;&quot;pqrstu&quot;&lt;/span&gt;

unable to fetch the kubeadm-config ConfigMap:
configmaps &lt;span class=&quot;s2&quot;&gt;&quot;kubeadm-config&quot;&lt;/span&gt; is forbidden:
User &lt;span class=&quot;s2&quot;&gt;&quot;system:bootstrap:pqrstu&quot;&lt;/span&gt; cannot get resource &lt;span class=&quot;s2&quot;&gt;&quot;configmaps&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;namespace &lt;span class=&quot;s2&quot;&gt;&quot;kube-system&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And we are also able to see where is the problem - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;User &quot;system:bootstrap:pqrstu&quot; cannot get resource &quot;configmaps&quot; in namespace &quot;kube-system&quot;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So, we know now when we pass the token to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubeadm join&lt;/code&gt; command, the API Server sees our requests as coming from the user &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system:bootstrap:pqrstu&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;ok, let’s try to fix it now by giving it the required permissions.&lt;/p&gt;

&lt;p&gt;We know that kubernetes uses RBAC to configure these kind of permissions on the kubernetes objects.&lt;br /&gt;
(and once again, I looked at another multi-node kind cluster to see what permissions we are missing and came up with the following template).&lt;/p&gt;

&lt;p&gt;I created a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClusterRoleBinding&lt;/code&gt; object that allowed the user (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system:bootstrap:pqrstu&lt;/code&gt;) to read cluster configuration.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;AND PLEASE NOTE:&lt;/strong&gt; This is not something I would do in a real cluster. This is purely just to move forward with this test!&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# clusterrolebinding-bootstrap-token.yaml&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;apiVersion&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;rbac.authorization.k8s.io/v1&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ClusterRoleBinding&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;allow-bootstrap-read-kubeadm-config&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;subjects&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;User&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;system:bootstrap:pqrstu&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;roleRef&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ClusterRole&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cluster-admin&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;apiGroup&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;rbac.authorization.k8s.io&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Apply it to the cluster:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ kubectl apply &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; clusterrolebinding-bootstrap-token.yaml 
clusterrolebinding.rbac.authorization.k8s.io/allow-bootstrap-read-kubeadm-config created

❯ kubectl get clusterrolebinding allow-bootstrap-read-kubeadm-config &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; kube-system 
NAME                                  ROLE                        AGE
allow-bootstrap-read-kubeadm-config   ClusterRole/cluster-admin   49s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, we have configured more permissions for our user &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system:bootstrap:pqrstu&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let’s re-run the same same command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@83ab08acf723:/# kubeadm &lt;span class=&quot;nb&quot;&gt;join &lt;/span&gt;172.18.0.2:6443 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--token&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;pqrstu.abcdef1234567890&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;--discovery-token-unsafe-skip-ca-verification&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--v&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;9
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Voila!&lt;br /&gt;
This time it worked successfully.&lt;br /&gt;
The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubeadm join&lt;/code&gt; ran successfully and retured - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;This node has joined the cluster&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I can confirm it from the Kind cluster’s control-plane node as well.&lt;br /&gt;
I can see this new docker container showing up as a node.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ kubectl get nodes 
NAME                 STATUS     ROLES           AGE    VERSION
83ab08acf723         NotReady   &amp;lt;none&amp;gt;          108s   v1.35.0-alpha.2.488+f35f9509a69cc6
kind-control-plane   Ready      control-plane   106m   v1.34.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;details&gt;
  Please see the full logs here. These contain all the requests showing how and where the Kubeadm token is used, as request's headers. (click to expand)

  &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@83ab08acf723:/# kubeadm &lt;span class=&quot;nb&quot;&gt;join &lt;/span&gt;172.18.0.2:6443   &lt;span class=&quot;nt&quot;&gt;--token&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;pqrstu.abcdef1234567890&quot;&lt;/span&gt;   &lt;span class=&quot;nt&quot;&gt;--discovery-token-unsafe-skip-ca-verification&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--v&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;9
I1215 14:50:15.160788     230 join.go:423] &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;preflight] found NodeName empty&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; using OS &lt;span class=&quot;nb&quot;&gt;hostname &lt;/span&gt;as NodeName
I1215 14:50:15.161142     230 initconfiguration.go:122] detected and using CRI socket: unix:///var/run/containerd/containerd.sock
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;preflight] Running pre-flight checks
I1215 14:50:15.161266     230 preflight.go:93] &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;preflight] Running general checks
I1215 14:50:15.161321     230 checks.go:315] validating the existence of file /etc/kubernetes/kubelet.conf
I1215 14:50:15.161355     230 checks.go:315] validating the existence of file /etc/kubernetes/bootstrap-kubelet.conf
I1215 14:50:15.161382     230 checks.go:89] validating the container runtime
I1215 14:50:15.167560     230 checks.go:120] validating the container runtime version compatibility
I1215 14:50:15.170013     230 checks.go:685] validating whether swap is enabled or not
	&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;WARNING Swap]: swap is supported &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;cgroup v2 only. The kubelet must be properly configured to use swap. Please refer to https://kubernetes.io/docs/concepts/architecture/nodes/#swap-memory, or disable swap on the node
I1215 14:50:15.170160     230 checks.go:405] validating the presence of executable losetup
I1215 14:50:15.170232     230 checks.go:405] validating the presence of executable mount
I1215 14:50:15.170257     230 checks.go:405] validating the presence of executable &lt;span class=&quot;nb&quot;&gt;cp
&lt;/span&gt;I1215 14:50:15.170278     230 checks.go:551] running system verification checks
I1215 14:50:15.231856     230 checks.go:436] checking whether the given node name is valid and reachable using net.LookupHost
I1215 14:50:15.232022     230 checks.go:651] validating kubelet version
I1215 14:50:15.276735     230 checks.go:165] validating &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;the &lt;span class=&quot;s2&quot;&gt;&quot;kubelet&quot;&lt;/span&gt; service is enabled and active
I1215 14:50:15.294376     230 checks.go:238] validating availability of port 10250
I1215 14:50:15.294632     230 checks.go:315] validating the existence of file /etc/kubernetes/pki/ca.crt
I1215 14:50:15.294661     230 checks.go:465] validating &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;the connectivity &lt;span class=&quot;nb&quot;&gt;type &lt;/span&gt;is via proxy or direct
I1215 14:50:15.294728     230 checks.go:364] validating the contents of file /proc/sys/net/ipv4/ip_forward
I1215 14:50:15.294770     230 join.go:553] &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;preflight] Discovering cluster-info
I1215 14:50:15.294792     230 token.go:71] &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;discovery] Created cluster-info discovery client, requesting info from &lt;span class=&quot;s2&quot;&gt;&quot;172.18.0.2:6443&quot;&lt;/span&gt;
I1215 14:50:15.294942     230 envvar.go:172] &lt;span class=&quot;s2&quot;&gt;&quot;Feature gate default state&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;feature&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;InOrderInformersBatchProcess&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;true
&lt;/span&gt;I1215 14:50:15.294959     230 envvar.go:172] &lt;span class=&quot;s2&quot;&gt;&quot;Feature gate default state&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;feature&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;InformerResourceVersion&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;true
&lt;/span&gt;I1215 14:50:15.294967     230 envvar.go:172] &lt;span class=&quot;s2&quot;&gt;&quot;Feature gate default state&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;feature&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;WatchListClient&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;false
&lt;/span&gt;I1215 14:50:15.294976     230 envvar.go:172] &lt;span class=&quot;s2&quot;&gt;&quot;Feature gate default state&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;feature&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ClientsAllowCBOR&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;false
&lt;/span&gt;I1215 14:50:15.294984     230 envvar.go:172] &lt;span class=&quot;s2&quot;&gt;&quot;Feature gate default state&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;feature&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ClientsPreferCBOR&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;false
&lt;/span&gt;I1215 14:50:15.294991     230 envvar.go:172] &lt;span class=&quot;s2&quot;&gt;&quot;Feature gate default state&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;feature&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;InOrderInformers&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;enabled&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;true
&lt;/span&gt;I1215 14:50:15.295371     230 token.go:229] &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;discovery] Waiting &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;the cluster-info ConfigMap to receive a JWS signature &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;token ID &lt;span class=&quot;s2&quot;&gt;&quot;pqrstu&quot;&lt;/span&gt;
I1215 14:50:15.295452     230 type.go:165] &lt;span class=&quot;s2&quot;&gt;&quot;Request Body&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;
I1215 14:50:15.295539     230 round_trippers.go:527] &lt;span class=&quot;s2&quot;&gt;&quot;Request&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;curlCommand&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;lt;
	curl &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-XGET&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Accept: application/vnd.kubernetes.protobuf,application/json&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;User-Agent: kubeadm/v1.35.0 (linux/amd64) kubernetes/f35f950&quot;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://172.18.0.2:6443/api/v1/namespaces/kube-public/configmaps/cluster-info?timeout=10s'&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
I1215 14:50:15.295931     230 round_trippers.go:562] &lt;span class=&quot;s2&quot;&gt;&quot;HTTP Trace: Dial succeed&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;network&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;tcp&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;172.18.0.2:6443&quot;&lt;/span&gt;
I1215 14:50:15.302680     230 round_trippers.go:632] &lt;span class=&quot;s2&quot;&gt;&quot;Response&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;verb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;GET&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://172.18.0.2:6443/api/v1/namespaces/kube-public/configmaps/cluster-info?timeout=10s&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;200 OK&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;lt;
	Audit-Id: 6c3035a3-0824-415c-8e5d-0db271cdb29f
	Cache-Control: no-cache, private
	Content-Length: 2102
	Content-Type: application/vnd.kubernetes.protobuf
	Date: Mon, 15 Dec 2025 14:50:15 GMT
	X-Kubernetes-Pf-Flowschema-Uid: f54c5d84-c2d8-4cbb-8801-07adb48ce73d
	X-Kubernetes-Pf-Prioritylevel-Uid: 7df0c0a7-2f8a-40ca-9625-0b6635feccd2
 &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;milliseconds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;7 &lt;span class=&quot;nv&quot;&gt;dnsLookupMilliseconds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0 &lt;span class=&quot;nv&quot;&gt;dialMilliseconds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0 &lt;span class=&quot;nv&quot;&gt;tlsHandshakeMilliseconds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;4 &lt;span class=&quot;nv&quot;&gt;serverProcessingMilliseconds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;2
I1215 14:50:15.302857     230 type.go:165] &lt;span class=&quot;s2&quot;&gt;&quot;Response Body&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;lt;
	00000000  6b 38 73 00 0a 0f 0a 02  76 31 12 09 43 6f 6e 66  |k8s.....v1..Conf|
	00000010  69 67 4d 61 70 12 9a 10  0a 99 02 0a 0c 63 6c 75  |igMap........clu|
	00000020  73 74 65 72 2d 69 6e 66  6f 12 00 1a 0b 6b 75 62  |ster-info....kub|
	00000030  65 2d 70 75 62 6c 69 63  22 00 2a 24 38 34 37 38  |e-public&lt;span class=&quot;s2&quot;&gt;&quot;.*&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$8478&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;|
	00000040  65 64 38 35 2d 62 61 66  39 2d 34 63 63 61 2d 38  |ed85-baf9-4cca-8|
	00000050  31 65 32 2d 37 35 36 66  62 39 61 61 65 62 62 61  |1e2-756fb9aaebba|
	00000060  32 04 38 34 33 35 38 00  42 08 08 d7 da ff c9 06  |2.84358.B.......|
	00000070  10 00 8a 01 54 0a 07 6b  75 62 65 61 64 6d 12 06  |....T..kubeadm..|
	00000080  55 70 64 61 74 65 1a 02  76 31 22 08 08 d7 da ff  |Update..v1&quot;&lt;/span&gt;.....|
	00000090  c9 06 10 00 32 08 46 69  65 6c 64 73 56 31 3a 27  |....2.FieldsV1:&lt;span class=&quot;s1&quot;&gt;'|
	000000a0  0a 25 7b 22 66 3a 64 61  74 61 22 3a 7b 22 2e 22  |.%{&quot;f:data&quot;:{&quot;.&quot;|
	000000b0  3a 7b 7d 2c 22 66 3a 6b  75 62 65 63 6f 6e 66 69  |:{},&quot;f:kubeconfi|
	000000c0  67 22 3a 7b 7d 7d 7d 42  00 8a 01 68 0a 17 6b 75  |g&quot;:{}}}B...h..ku|
	000000d0  62 65 2d 63 6f 6e 74 72  6f 6c 6c 65 72 2d 6d 61  |be-controller-ma|
	000000e0  6e 61 67 65 72 12 06 55  70 64 61 74 65 1a 02 76  |nager..Update..v|
	000000f0  31 22 08 08 a8 87 80 ca  06 10 00 32 08 46 69 65  |1&quot;.........2.Fie|
	00000100  6c 64 73 56 31 3a 2b 0a  29 7b 22 66 3a 64 61 74  |ldsV1:+.){&quot;f:dat|
	00000110  61 22 3a 7b 22 66 3a 6a  77 73 2d 6b 75 62 65 63  |a&quot;:{&quot;f:jws-kubec|
	00000120  6f 6e 66 69 67 2d 70 71  72 73 74 75 22 3a 7b 7d  |onfig-pqrstu&quot;:{}|
	00000130  7d 7d 42 00 12 6e 0a 15  6a 77 73 2d 6b 75 62 65  |}}B..n..jws-kube|
	00000140  63 6f 6e 66 69 67 2d 70  71 72 73 74 75 12 55 65  |config-pqrstu.Ue|
	00000150  79 4a 68 62 47 63 69 4f  69 4a 49 55 7a 49 31 4e  |yJhbGciOiJIUzI1N|
	00000160  69 49 73 49 6d 74 70 5a  43 49 36 49 6e 42 78 63  |iIsImtpZCI6InBxc|
	00000170  6e 4e 30 64 53 4a 39 2e  2e 75 5f 4d 74 56 4f 42  |nN0dSJ9..u_MtVOB|
	00000180  69 68 65 4e 5a 37 5a 57  31 5f 5a 36 52 6d 67 78  |iheNZ7ZW1_Z6Rmgx|
	00000190  35 50 41 5f 69 76 6b 77  31 2d 62 46 53 35 49 50  |5PA_ivkw1-bFS5IP|
	000001a0  71 33 34 55 12 8b 0d 0a  0a 6b 75 62 65 63 6f 6e  |q34U.....kubecon|
	000001b0  66 69 67 12 fc 0c 61 70  69 56 65 72 73 69 6f 6e  |fig...apiVersion|
	000001c0  3a 20 76 31 0a 63 6c 75  73 74 65 72 73 3a 0a 2d  |: v1.clusters:.-|
	000001d0  20 63 6c 75 73 74 65 72  3a 0a 20 20 20 20 63 65  | cluster:.    ce|
	000001e0  72 74 69 66 69 63 61 74  65 2d 61 75 74 68 6f 72  |rtificate-author|
	000001f0  69 74 79 2d 64 61 74 61  3a 20 4c 53 30 74 4c 53  |ity-data: LS0tLS|
	00000200  31 43 52 55 64 4a 54 69  42 44 52 56 4a 55 53 55  |1CRUdJTiBDRVJUSU|
	00000210  5a 4a 51 30 46 55 52 53  30 74 4c 53 30 74 43 6b  |ZJQ0FURS0tLS0tCk|
	00000220  31 4a 53 55 52 43 56 45  4e 44 51 57 55 79 5a 30  |1JSURCVENDQWUyZ0|
	00000230  46 33 53 55 4a 42 5a 30  6c 4a 55 46 70 36 4e 31  |F3SUJBZ0lJUFp6N1|
	00000240  5a 44 52 7a 6c 4b 64 6b  31 33 52 46 46 5a 53 6b  |ZDRzlKdk13RFFZSk|
	00000250  74 76 57 6b 6c 6f 64 6d  4e 4f 51 56 46 46 54 45  |tvWklodmNOQVFFTE|
	00000260  4a 52 51 58 64 47 56 45  56 55 54 55 4a 46 52 30  |JRQXdGVEVUTUJFR0|
	00000270  45 78 56 55 55 4b 51 58  68 4e 53 32 45 7a 56 6d  |ExVUUKQXhNS2EzVm|
	00000280  6c 61 57 45 70 31 57 6c  68 53 62 47 4e 36 51 57  |laWEp1WlhSbGN6QW|
	00000290  56 47 64 7a 42 35 54 6c  52 46 65 55 31 55 56 58  |VGdzB5TlRFeU1UVX|
	000002a0  68 4e 56 45 45 30 54 56  52 57 59 55 5a 33 4d 48  |hNVEE0TVRWYUZ3MH|
	000002b0  70 4f 56 45 56 35 54 56  52 4e 65 45 31 55 52 58  |pOVEV5TVRNeE1URX|
	000002c0  70 4e 56 46 5a 68 54 55  4a 56 65 41 70 46 65 6b  |pNVFZhTUJVeApFek|
	000002d0  46 53 51 6d 64 4f 56 6b  4a 42 54 56 52 44 62 58  |FSQmdOVkJBTVRDbX|
	000002e0  51 78 57 57 31 57 65 57  4a 74 56 6a 42 61 57 45  |QxWW1WeWJtVjBaWE|
	000002f0  31 33 5a 32 64 46 61 55  31 42 4d 45 64 44 55 33  |13Z2dFaU1BMEdDU3|
	00000300  46 48 55 30 6c 69 4d 30  52 52 52 55 4a 42 55 56  |FHU0liM0RRRUJBUV|
	00000310  56 42 51 54 52 4a 51 6b  52 33 51 58 64 6e 5a 30  |VBQTRJQkR3QXdnZ0|
	00000320  56 4c 43 6b 46 76 53 55  4a 42 55 55 52 34 4d 6a  |VLCkFvSUJBUUR4Mj|
	00000330  56 79 64 55 35 61 54 6e  42 70 62 6a 68 30 51 54  |VydU5aTnBpbjh0QT|
	00000340  46 4d 52 6d 39 71 4e 31  6c 74 4e 44 56 6b 4d 30  |FMRm9qN1ltNDVkM0|
	00000350  4e 30 65 56 42 71 57 47  73 30 53 6d 4a 31 54 46  |N0eVBqWGs0SmJ1TF|
	00000360  70 53 56 55 55 33 61 6e  6c 59 53 7a 64 6d 4d 6e  |pSVUU3anlYSzdmMn|
	00000370  70 49 53 44 45 35 4d 46  59 4b 54 58 42 36 4e 31  |pISDE5MFYKTXB6N1|
	00000380  46 59 62 7a 64 32 53 31  70 6f 65 46 6c 70 55 7a  |FYbzd2S1poeFlpUz|
	00000390  64 46 61 46 52 4d 65 56  4e 6d 4f 47 68 6f 53 32  |dFaFRMeVNmOGhoS2|
	000003a0  59 34 56 32 55 34 5a 6b  6c 58 55 6b 46 45 4f 56  |Y4V2U4ZklXUkFEOV|
	000003b0  6c 55 56 57 70 61 59 6c  4a 6a 63 6a 4e 6f 52 46  |lUVWpaYlJjcjNoRF|
	000003c0  6f 72 57 44 68 6c 62 47  70 78 52 48 41 31 51 51  |orWDhlbGpxRHA1QQ|
	000003d0  70 52 65 44 4e 34 62 32  52 55 4d 6c 68 4c 4e 31  |pReDN4b2RUMlhLN1|
	000003e0  56 72 54 6e 68 50 64 6d  39 36 5a 58 68 42 4c 32  |VrTnhPdm96ZXhBL2|
	000003f0  74 53 4f 58 6c 78 65 6d  4a 72 57 56 70 7a 61 30  |tSOXlxemJrWVpza0|
	00000400  46 42 59 58 46 5a 51 54  4e 71 52 7a 42 4a 63 56  |FBYXFZQTNqRzBJcV|
	00000410  4e 46 51 58 68 4c 52 56  68 4c 57 6e 64 4d 4d 6d  |NFQXhLRVhLWndMMm|
	00000420  77 77 59 32 45 77 43 6e  70 4b 52 6a 6c 6e 62 54  |wwY2EwCnpKRjlnbT|
	00000430  4e 33 64 33 68 4f 55 47  64 49 53 57 4e 73 4e 57  |N3d3hOUGdISWNsNW|
	00000440  68 68 63 45 56 46 4e 54  56 36 63 30 67 77 65 47  |hhcEVFNTV6c0gweG|
	00000450  68 76 57 58 64 4b 5a 32  78 53 4f 57 31 6d 5a 6c  |hvWXdKZ2xSOW1mZl|
	00000460  64 4e 4e 7a 68 6b 52 32  4d 78 55 33 68 79 52 57  |dNNzhkR2MxU3hyRW|
	00000470  46 30 65 6d 5a 52 4f 44  46 72 59 55 77 4b 56 6b  |F0emZRODFrYUwKVk|
	00000480  52 50 5a 30 56 6b 62 58  4e 4b 65 48 52 4a 55 32  |RPZ0VkbXNKeHRJU2|
	00000490  45 31 53 6d 74 43 54 58  56 52 5a 7a 56 52 57 57  |E1SmtCTXVRZzVRWW|
	000004a0  39 43 51 57 4e 78 55 30  6b 31 64 33 52 30 4e 47  |9CQWNxU0k1d3R0NG|
	000004b0  6b 34 61 6c 6f 76 64 6e  70 45 64 6d 56 36 4e 48  |k4alovdnpEdmV6NH|
	000004c0  67 33 55 45 64 77 63 56  70 5a 56 54 5a 4c 54 33  |g3UEdwcVpZVTZLT3|
	000004d0  6c 48 5a 67 70 75 64 46  42 4a 55 55 49 33 64 55  |lHZgpudFBJUUI3dU|
	000004e0  46 6f 52 57 78 4d 65 46  52 53 4b 7a 4a 68 57 54  |FoRWxMeFRSKzJhWT|
	000004f0  63 7a 53 55 39 73 63 56  6b 76 51 57 64 4e 51 6b  |czSU9scVkvQWdNQk|
	00000500  46 42 52 32 70 58 56 45  4a 59 54 55 45 30 52 30  |FBR2pXVEJYTUE0R0|
	00000510  45 78 56 57 52 45 64 30  56 43 4c 33 64 52 52 55  |ExVWREd0VCL3dRRU|
	00000520  46 33 53 55 4e 77 52 45  46 51 43 6b 4a 6e 54 6c  |F3SUNwREFQCkJnTl|
	00000530  5a 49 55 6b 31 43 51 57  59 34 52 55 4a 55 51 55  |ZIUk1CQWY4RUJUQU|
	00000540  52 42 55 55 67 76 54 55  49 77 52 30 45 78 56 57  |RBUUgvTUIwR0ExVW|
	00000550  52 45 5a 31 46 58 51 6b  4a 53 55 79 39 56 4e 44  |REZ1FXQkJSUy9VND|
	00000560  4e 73 59 6a 51 32 62 45  70 74 52 48 6b 78 57 56  |NsYjQ2bEptRHkxWV|
	00000570  42 7a 56 6e 64 43 4d 31  4a 44 55 44 52 45 51 56  |BzVndCM1JDUDREQV|
	00000580  59 4b 51 6d 64 4f 56 6b  68 53 52 55 56 45 61 6b  |YKQmdOVkhSRUVEak|
	00000590  46 4e 5a 32 64 77 63 6d  52 58 53 6d 78 6a 62 54  |FNZ2dwcmRXSmxjbT|
	000005a0  56 73 5a 45 64 57 65 6b  31 42 4d 45 64 44 55 33  |VsZEdWek1BMEdDU3|
	000005b0  46 48 55 30 6c 69 4d 30  52 52 52 55 4a 44 64 31  |FHU0liM0RRRUJDd1|
	000005c0  56 42 51 54 52 4a 51 6b  46 52 51 33 56 34 64 31  |VBQTRJQkFRQ3V4d1|
	000005d0  46 4a 54 6a 64 6f 61 41  70 59 59 6d 52 4c 63 30  |FJTjdoaApYYmRLc0|
	000005e0  39 72 56 33 42 42 52 46  68 75 59 57 35 4f 57 48  |9rV3BBRFhuYW5OWH|
	000005f0  5a 4b 63 45 52 6b 54 57  38 35 61 47 38 79 54 58  |ZKcERkTW85aG8yTX|
	00000600  70 77 63 55 78 30 4f 58  46 6b 61 55 52 61 59 6b  |pwcUx0OXFkaURaYk|
	00000610  78 76 63 44 52 44 59 6e  67 72 63 30 70 53 59 7a  |xvcDRDYngrc0pSYz|
	00000620  6c 6d 62 33 4e 59 52 7a  56 58 61 6a 46 56 43 6b  |lmb3NYRzVXajFVCk|
	00000630  46 79 62 6e 6c 6a 5a 6b  6c 34 62 6b 5a 56 4d 57  |FybnljZkl4bkZVMW|
	00000640  74 70 53 48 4e 6e 64 32  55 35 4e 47 35 43 59 55  |tpSHNnd2U5NG5CYU|
	00000650  64 6a 59 56 4e 44 63 58  64 54 62 55 56 49 65 44  |djYVNDcXdTbUVIeD|
	00000660  52 73 4d 56 5a 36 53 69  74 6c 64 30 35 57 62 32  |RsMVZ6Sitld05Wb2|
	00000670  34 34 63 6e 42 75 55 30  74 59 65 47 46 52 55 33  |44cnBuU0tYeGFRU3|
	00000680  41 30 4e 6d 55 4b 4b 30  64 69 64 55 31 34 55 48  |A0NmUKK0didU14UH|
	00000690  64 56 5a 46 6c 69 64 6a  5a 32 57 44 4a 43 64 7a  |dVZFlidjZ2WDJCdz|
	000006a0  56 70 64 33 64 43 61 56  42 32 4f 57 78 43 4f 44  |Vpd3dCaVB2OWxCOD|
	000006b0  45 7a 54 6e 4a 6e 61 31  52 5a 4b 30 46 70 65 55  |EzTnJna1RZK0FpeU|
	000006c0  70 47 61 33 64 79 62 6a  46 51 53 6d 4e 55 64 6d  |pGa3dybjFQSmNUdm|
	000006d0  64 74 64 55 4a 4e 53 6b  34 7a 52 77 70 79 63 45  |dtdUJNSk4zRwpycE|
	000006e0  74 4d 55 48 6b 32 55 7a  4a 7a 4f 44 49 35 62 54  |tMUHk2UzJzODI5bT|
	000006f0  64 57 63 45 77 7a 4f 55  4d 30 4d 47 74 54 62 45  |dWcEwzOUM0MGtTbE|
	00000700  39 42 59 6d 78 4a 52 56  70 50 53 55 56 32 63 6d  |9BYmxJRVpPSUV2cm|
	00000710  46 44 65 56 68 58 54 32  68 55 62 47 56 56 56 6c  |FDeVhXT2hUbGVVVl|
	00000720  56 4c 5a 48 42 50 4e 56  5a 34 55 30 67 76 5a 56  |VLZHBPNVZ4U0gvZV|
	00000730  46 45 43 6c 64 48 57 6e  46 76 53 6a 42 35 57 56  |FECldHWnFvSjB5WV|
	00000740  4e 52 54 47 74 48 54 43  38 78 52 79 39 71 52 32  |NRTGtHTC8xRy9qR2|
	00000750  56 6c 51 57 68 4b 62 6e  56 72 4f 56 70 73 4e 54  |VlQWhKbnVrOVpsNT|
	00000760  63 79 4e 6a 63 77 62 48  4e 71 56 48 46 4d 51 55  |cyNjcwbHNqVHFMQU|
	00000770  35 68 55 69 74 58 53 30  64 47 64 7a 46 4a 4d 6e  |5hUitXS0dGdzFJMn|
	00000780  52 7a 57 56 5a 49 54 45  38 4b 62 57 35 4c 54 6e  |RzWVZITE8KbW5LTn|
	00000790  42 49 61 79 74 72 56 56  4a 34 43 69 30 74 4c 53  |BIaytrVVJ4Ci0tLS|
	000007a0  30 74 52 55 35 45 49 45  4e 46 55 6c 52 4a 52 6b  |0tRU5EIENFUlRJRk|
	000007b0  6c 44 51 56 52 46 4c 53  30 74 4c 53 30 4b 0a 20  |lDQVRFLS0tLS0K. |
	000007c0  20 20 20 73 65 72 76 65  72 3a 20 68 74 74 70 73  |   server: https|
	000007d0  3a 2f 2f 6b 69 6e 64 2d  63 6f 6e 74 72 6f 6c 2d  |://kind-control-|
	000007e0  70 6c 61 6e 65 3a 36 34  34 33 0a 20 20 6e 61 6d  |plane:6443.  nam|
	000007f0  65 3a 20 22 22 0a 63 6f  6e 74 65 78 74 73 3a 20  |e: &quot;&quot;.contexts: |
	00000800  6e 75 6c 6c 0a 63 75 72  72 65 6e 74 2d 63 6f 6e  |null.current-con|
	00000810  74 65 78 74 3a 20 22 22  0a 6b 69 6e 64 [truncated 178 chars]
 &amp;gt;
I1215 14:50:15.303934     230 token.go:113] [discovery] Cluster info signature and contents are valid and no TLS pinning was specified, will use API Server &quot;172.18.0.2:6443&quot;
I1215 14:50:15.303958     230 discovery.go:53] [discovery] Using provided TLSBootstrapToken as authentication credentials for the join process
I1215 14:50:15.303971     230 join.go:567] [preflight] Fetching init configuration
I1215 14:50:15.303980     230 join.go:681] [preflight] Retrieving KubeConfig objects
[preflight] Reading configuration from the &quot;kubeadm-config&quot; ConfigMap in namespace &quot;kube-system&quot;...
[preflight] Use '&lt;/span&gt;kubeadm init phase upload-config kubeadm &lt;span class=&quot;nt&quot;&gt;--config&lt;/span&gt; your-config-file&lt;span class=&quot;s1&quot;&gt;' to re-upload it.
I1215 14:50:15.304427     230 type.go:165] &quot;Request Body&quot; body=&quot;&quot;
I1215 14:50:15.304525     230 round_trippers.go:527] &quot;Request&quot; curlCommand=&amp;lt;
	curl -v -XGET  -H &quot;Accept: application/vnd.kubernetes.protobuf,application/json&quot; -H &quot;User-Agent: kubeadm/v1.35.0 (linux/amd64) kubernetes/f35f950&quot; -H &quot;Authorization: Bearer &amp;lt;masked&amp;gt;&quot; '&lt;/span&gt;https://kind-control-plane:6443/api/v1/namespaces/kube-system/configmaps/kubeadm-config?timeout&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;10s&lt;span class=&quot;s1&quot;&gt;'
 &amp;gt;
I1215 14:50:15.305280     230 round_trippers.go:547] &quot;HTTP Trace: DNS Lookup resolved&quot; host=&quot;kind-control-plane&quot; address=[{&quot;IP&quot;:&quot;172.18.0.2&quot;,&quot;Zone&quot;:&quot;&quot;},{&quot;IP&quot;:&quot;fc00:****::2&quot;,&quot;Zone&quot;:&quot;&quot;}]
I1215 14:50:15.305519     230 round_trippers.go:562] &quot;HTTP Trace: Dial succeed&quot; network=&quot;tcp&quot; address=&quot;172.18.0.2:6443&quot;
I1215 14:50:15.312270     230 round_trippers.go:632] &quot;Response&quot; verb=&quot;GET&quot; url=&quot;https://kind-control-plane:6443/api/v1/namespaces/kube-system/configmaps/kubeadm-config?timeout=10s&quot; status=&quot;200 OK&quot; headers=&amp;lt;
	Audit-Id: dc851cb8-00d2-499a-9d93-791b645d3175
	Cache-Control: no-cache, private
	Content-Length: 935
	Content-Type: application/vnd.kubernetes.protobuf
	Date: Mon, 15 Dec 2025 14:50:15 GMT
	X-Kubernetes-Pf-Flowschema-Uid: f54c5d84-c2d8-4cbb-8801-07adb48ce73d
	X-Kubernetes-Pf-Prioritylevel-Uid: 7df0c0a7-2f8a-40ca-9625-0b6635feccd2
 &amp;gt; milliseconds=7 dnsLookupMilliseconds=0 dialMilliseconds=0 tlsHandshakeMilliseconds=4 serverProcessingMilliseconds=2
I1215 14:50:15.312385     230 type.go:165] &quot;Response Body&quot; body=&amp;lt;
	00000000  6b 38 73 00 0a 0f 0a 02  76 31 12 09 43 6f 6e 66  |k8s.....v1..Conf|
	00000010  69 67 4d 61 70 12 8b 07  0a b9 01 0a 0e 6b 75 62  |igMap........kub|
	00000020  65 61 64 6d 2d 63 6f 6e  66 69 67 12 00 1a 0b 6b  |eadm-config....k|
	00000030  75 62 65 2d 73 79 73 74  65 6d 22 00 2a 24 38 66  |ube-system&quot;.*$8f|
	00000040  37 61 38 66 35 34 2d 37  39 62 65 2d 34 34 61 35  |7a8f54-79be-44a5|
	00000050  2d 61 63 35 63 2d 34 34  32 34 64 33 66 37 39 39  |-ac5c-4424d3f799|
	00000060  30 39 32 03 32 30 37 38  00 42 08 08 d7 da ff c9  |092.2078.B......|
	00000070  06 10 00 8a 01 5e 0a 07  6b 75 62 65 61 64 6d 12  |.....^..kubeadm.|
	00000080  06 55 70 64 61 74 65 1a  02 76 31 22 08 08 d7 da  |.Update..v1&quot;....|
	00000090  ff c9 06 10 00 32 08 46  69 65 6c 64 73 56 31 3a  |.....2.FieldsV1:|
	000000a0  31 0a 2f 7b 22 66 3a 64  61 74 61 22 3a 7b 22 2e  |1./{&quot;f:data&quot;:{&quot;.|
	000000b0  22 3a 7b 7d 2c 22 66 3a  43 6c 75 73 74 65 72 43  |&quot;:{},&quot;f:ClusterC|
	000000c0  6f 6e 66 69 67 75 72 61  74 69 6f 6e 22 3a 7b 7d  |onfiguration&quot;:{}|
	000000d0  7d 7d 42 00 12 cc 05 0a  14 43 6c 75 73 74 65 72  |}}B......Cluster|
	000000e0  43 6f 6e 66 69 67 75 72  61 74 69 6f 6e 12 b3 05  |Configuration...|
	000000f0  61 70 69 53 65 72 76 65  72 3a 0a 20 20 63 65 72  |apiServer:.  cer|
	00000100  74 53 41 4e 73 3a 0a 20  20 2d 20 6c 6f 63 61 6c  |tSANs:.  - local|
	00000110  68 6f 73 74 0a 20 20 2d  20 31 32 37 2e 30 2e 30  |host.  - 127.0.0|
	00000120  2e 31 0a 20 20 65 78 74  72 61 41 72 67 73 3a 0a  |.1.  extraArgs:.|
	00000130  20 20 2d 20 6e 61 6d 65  3a 20 72 75 6e 74 69 6d  |  - name: runtim|
	00000140  65 2d 63 6f 6e 66 69 67  0a 20 20 20 20 76 61 6c  |e-config.    val|
	00000150  75 65 3a 20 22 22 0a 61  70 69 56 65 72 73 69 6f  |ue: &quot;&quot;.apiVersio|
	00000160  6e 3a 20 6b 75 62 65 61  64 6d 2e 6b 38 73 2e 69  |n: kubeadm.k8s.i|
	00000170  6f 2f 76 31 62 65 74 61  34 0a 63 61 43 65 72 74  |o/v1beta4.caCert|
	00000180  69 66 69 63 61 74 65 56  61 6c 69 64 69 74 79 50  |ificateValidityP|
	00000190  65 72 69 6f 64 3a 20 38  37 36 30 30 68 30 6d 30  |eriod: 87600h0m0|
	000001a0  73 0a 63 65 72 74 69 66  69 63 61 74 65 56 61 6c  |s.certificateVal|
	000001b0  69 64 69 74 79 50 65 72  69 6f 64 3a 20 38 37 36  |idityPeriod: 876|
	000001c0  30 68 30 6d 30 73 0a 63  65 72 74 69 66 69 63 61  |0h0m0s.certifica|
	000001d0  74 65 73 44 69 72 3a 20  2f 65 74 63 2f 6b 75 62  |tesDir: /etc/kub|
	000001e0  65 72 6e 65 74 65 73 2f  70 6b 69 0a 63 6c 75 73  |ernetes/pki.clus|
	000001f0  74 65 72 4e 61 6d 65 3a  20 6b 69 6e 64 0a 63 6f  |terName: kind.co|
	00000200  6e 74 72 6f 6c 50 6c 61  6e 65 45 6e 64 70 6f 69  |ntrolPlaneEndpoi|
	00000210  6e 74 3a 20 6b 69 6e 64  2d 63 6f 6e 74 72 6f 6c  |nt: kind-control|
	00000220  2d 70 6c 61 6e 65 3a 36  34 34 33 0a 63 6f 6e 74  |-plane:6443.cont|
	00000230  72 6f 6c 6c 65 72 4d 61  6e 61 67 65 72 3a 0a 20  |rollerManager:. |
	00000240  20 65 78 74 72 61 41 72  67 73 3a 0a 20 20 2d 20  | extraArgs:.  - |
	00000250  6e 61 6d 65 3a 20 65 6e  61 62 6c 65 2d 68 6f 73  |name: enable-hos|
	00000260  74 70 61 74 68 2d 70 72  6f 76 69 73 69 6f 6e 65  |tpath-provisione|
	00000270  72 0a 20 20 20 20 76 61  6c 75 65 3a 20 22 74 72  |r.    value: &quot;tr|
	00000280  75 65 22 0a 64 6e 73 3a  20 7b 7d 0a 65 6e 63 72  |ue&quot;.dns: {}.encr|
	00000290  79 70 74 69 6f 6e 41 6c  67 6f 72 69 74 68 6d 3a  |yptionAlgorithm:|
	000002a0  20 52 53 41 2d 32 30 34  38 0a 65 74 63 64 3a 0a  | RSA-2048.etcd:.|
	000002b0  20 20 6c 6f 63 61 6c 3a  0a 20 20 20 20 64 61 74  |  local:.    dat|
	000002c0  61 44 69 72 3a 20 2f 76  61 72 2f 6c 69 62 2f 65  |aDir: /var/lib/e|
	000002d0  74 63 64 0a 69 6d 61 67  65 52 65 70 6f 73 69 74  |tcd.imageReposit|
	000002e0  6f 72 79 3a 20 72 65 67  69 73 74 72 79 2e 6b 38  |ory: registry.k8|
	000002f0  73 2e 69 6f 0a 6b 69 6e  64 3a 20 43 6c 75 73 74  |s.io.kind: Clust|
	00000300  65 72 43 6f 6e 66 69 67  75 72 61 74 69 6f 6e 0a  |erConfiguration.|
	00000310  6b 75 62 65 72 6e 65 74  65 73 56 65 72 73 69 6f  |kubernetesVersio|
	00000320  6e 3a 20 76 31 2e 33 34  2e 30 0a 6e 65 74 77 6f  |n: v1.34.0.netwo|
	00000330  72 6b 69 6e 67 3a 0a 20  20 64 6e 73 44 6f 6d 61  |rking:.  dnsDoma|
	00000340  69 6e 3a 20 63 6c 75 73  74 65 72 2e 6c 6f 63 61  |in: cluster.loca|
	00000350  6c 0a 20 20 70 6f 64 53  75 62 6e 65 74 3a 20 31  |l.  podSubnet: 1|
	00000360  30 2e 32 34 34 2e 30 2e  30 2f 31 36 0a 20 20 73  |0.244.0.0/16.  s|
	00000370  65 72 76 69 63 65 53 75  62 6e 65 74 3a 20 31 30  |erviceSubnet: 10|
	00000380  2e 39 36 2e 30 2e 30 2f  31 36 0a 70 72 6f 78 79  |.96.0.0/16.proxy|
	00000390  3a 20 7b 7d 0a 73 63 68  65 64 75 6c 65 72 3a 20  |: {}.scheduler: |
	000003a0  7b 7d 0a 1a 00 22 00                              |{}...&quot;.|
 &amp;gt;
I1215 14:50:15.313552     230 kubeproxy.go:55] attempting to download the KubeProxyConfiguration from ConfigMap &quot;kube-proxy&quot;
I1215 14:50:15.313605     230 type.go:165] &quot;Request Body&quot; body=&quot;&quot;
I1215 14:50:15.313716     230 round_trippers.go:527] &quot;Request&quot; curlCommand=&amp;lt;
	curl -v -XGET  -H &quot;Authorization: Bearer &amp;lt;masked&amp;gt;&quot; -H &quot;Accept: application/vnd.kubernetes.protobuf,application/json&quot; -H &quot;User-Agent: kubeadm/v1.35.0 (linux/amd64) kubernetes/f35f950&quot; '&lt;/span&gt;https://kind-control-plane:6443/api/v1/namespaces/kube-system/configmaps/kube-proxy?timeout&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;10s&lt;span class=&quot;s1&quot;&gt;'
 &amp;gt;
I1215 14:50:15.315629     230 round_trippers.go:632] &quot;Response&quot; verb=&quot;GET&quot; url=&quot;https://kind-control-plane:6443/api/v1/namespaces/kube-system/configmaps/kube-proxy?timeout=10s&quot; status=&quot;200 OK&quot; headers=&amp;lt;
	Audit-Id: 7da1f078-b1a7-40b7-8b9d-595fb32485b5
	Cache-Control: no-cache, private
	Content-Length: 2089
	Content-Type: application/vnd.kubernetes.protobuf
	Date: Mon, 15 Dec 2025 14:50:15 GMT
	X-Kubernetes-Pf-Flowschema-Uid: f54c5d84-c2d8-4cbb-8801-07adb48ce73d
	X-Kubernetes-Pf-Prioritylevel-Uid: 7df0c0a7-2f8a-40ca-9625-0b6635feccd2
 &amp;gt; milliseconds=1 getConnectionMilliseconds=0 serverProcessingMilliseconds=1
I1215 14:50:15.315778     230 type.go:165] &quot;Response Body&quot; body=&amp;lt;
	00000000  6b 38 73 00 0a 0f 0a 02  76 31 12 09 43 6f 6e 66  |k8s.....v1..Conf|
	00000010  69 67 4d 61 70 12 8d 10  0a 85 02 0a 0a 6b 75 62  |igMap........kub|
	00000020  65 2d 70 72 6f 78 79 12  00 1a 0b 6b 75 62 65 2d  |e-proxy....kube-|
	00000030  73 79 73 74 65 6d 22 00  2a 24 34 31 37 66 31 65  |system&quot;.*$417f1e|
	00000040  38 32 2d 31 33 33 63 2d  34 65 38 32 2d 38 62 66  |82-133c-4e82-8bf|
	00000050  36 2d 38 66 34 36 34 31  33 31 33 61 66 37 32 03  |6-8f4641313af72.|
	00000060  32 33 38 38 00 42 08 08  d8 da ff c9 06 10 00 5a  |2388.B.........Z|
	00000070  11 0a 03 61 70 70 12 0a  6b 75 62 65 2d 70 72 6f  |...app..kube-pro|
	00000080  78 79 8a 01 9a 01 0a 07  6b 75 62 65 61 64 6d 12  |xy......kubeadm.|
	00000090  06 55 70 64 61 74 65 1a  02 76 31 22 08 08 d8 da  |.Update..v1&quot;....|
	000000a0  ff c9 06 10 00 32 08 46  69 65 6c 64 73 56 31 3a  |.....2.FieldsV1:|
	000000b0  6d 0a 6b 7b 22 66 3a 64  61 74 61 22 3a 7b 22 2e  |m.k{&quot;f:data&quot;:{&quot;.|
	000000c0  22 3a 7b 7d 2c 22 66 3a  63 6f 6e 66 69 67 2e 63  |&quot;:{},&quot;f:config.c|
	000000d0  6f 6e 66 22 3a 7b 7d 2c  22 66 3a 6b 75 62 65 63  |onf&quot;:{},&quot;f:kubec|
	000000e0  6f 6e 66 69 67 2e 63 6f  6e 66 22 3a 7b 7d 7d 2c  |onfig.conf&quot;:{}},|
	000000f0  22 66 3a 6d 65 74 61 64  61 74 61 22 3a 7b 22 66  |&quot;f:metadata&quot;:{&quot;f|
	00000100  3a 6c 61 62 65 6c 73 22  3a 7b 22 2e 22 3a 7b 7d  |:labels&quot;:{&quot;.&quot;:{}|
	00000110  2c 22 66 3a 61 70 70 22  3a 7b 7d 7d 7d 7d 42 00  |,&quot;f:app&quot;:{}}}}B.|
	00000120  12 d1 0a 0a 0b 63 6f 6e  66 69 67 2e 63 6f 6e 66  |.....config.conf|
	00000130  12 c1 0a 61 70 69 56 65  72 73 69 6f 6e 3a 20 6b  |...apiVersion: k|
	00000140  75 62 65 70 72 6f 78 79  2e 63 6f 6e 66 69 67 2e  |ubeproxy.config.|
	00000150  6b 38 73 2e 69 6f 2f 76  31 61 6c 70 68 61 31 0a  |k8s.io/v1alpha1.|
	00000160  62 69 6e 64 41 64 64 72  65 73 73 3a 20 30 2e 30  |bindAddress: 0.0|
	00000170  2e 30 2e 30 0a 62 69 6e  64 41 64 64 72 65 73 73  |.0.0.bindAddress|
	00000180  48 61 72 64 46 61 69 6c  3a 20 66 61 6c 73 65 0a  |HardFail: false.|
	00000190  63 6c 69 65 6e 74 43 6f  6e 6e 65 63 74 69 6f 6e  |clientConnection|
	000001a0  3a 0a 20 20 61 63 63 65  70 74 43 6f 6e 74 65 6e  |:.  acceptConten|
	000001b0  74 54 79 70 65 73 3a 20  22 22 0a 20 20 62 75 72  |tTypes: &quot;&quot;.  bur|
	000001c0  73 74 3a 20 30 0a 20 20  63 6f 6e 74 65 6e 74 54  |st: 0.  contentT|
	000001d0  79 70 65 3a 20 22 22 0a  20 20 6b 75 62 65 63 6f  |ype: &quot;&quot;.  kubeco|
	000001e0  6e 66 69 67 3a 20 2f 76  61 72 2f 6c 69 62 2f 6b  |nfig: /var/lib/k|
	000001f0  75 62 65 2d 70 72 6f 78  79 2f 6b 75 62 65 63 6f  |ube-proxy/kubeco|
	00000200  6e 66 69 67 2e 63 6f 6e  66 0a 20 20 71 70 73 3a  |nfig.conf.  qps:|
	00000210  20 30 0a 63 6c 75 73 74  65 72 43 49 44 52 3a 20  | 0.clusterCIDR: |
	00000220  31 30 2e 32 34 34 2e 30  2e 30 2f 31 36 0a 63 6f  |10.244.0.0/16.co|
	00000230  6e 66 69 67 53 79 6e 63  50 65 72 69 6f 64 3a 20  |nfigSyncPeriod: |
	00000240  30 73 0a 63 6f 6e 6e 74  72 61 63 6b 3a 0a 20 20  |0s.conntrack:.  |
	00000250  6d 61 78 50 65 72 43 6f  72 65 3a 20 30 0a 20 20  |maxPerCore: 0.  |
	00000260  6d 69 6e 3a 20 6e 75 6c  6c 0a 20 20 74 63 70 42  |min: null.  tcpB|
	00000270  65 4c 69 62 65 72 61 6c  3a 20 66 61 6c 73 65 0a  |eLiberal: false.|
	00000280  20 20 74 63 70 43 6c 6f  73 65 57 61 69 74 54 69  |  tcpCloseWaitTi|
	00000290  6d 65 6f 75 74 3a 20 6e  75 6c 6c 0a 20 20 74 63  |meout: null.  tc|
	000002a0  70 45 73 74 61 62 6c 69  73 68 65 64 54 69 6d 65  |pEstablishedTime|
	000002b0  6f 75 74 3a 20 6e 75 6c  6c 0a 20 20 75 64 70 53  |out: null.  udpS|
	000002c0  74 72 65 61 6d 54 69 6d  65 6f 75 74 3a 20 30 73  |treamTimeout: 0s|
	000002d0  0a 20 20 75 64 70 54 69  6d 65 6f 75 74 3a 20 30  |.  udpTimeout: 0|
	000002e0  73 0a 64 65 74 65 63 74  4c 6f 63 61 6c 3a 0a 20  |s.detectLocal:. |
	000002f0  20 62 72 69 64 67 65 49  6e 74 65 72 66 61 63 65  | bridgeInterface|
	00000300  3a 20 22 22 0a 20 20 69  6e 74 65 72 66 61 63 65  |: &quot;&quot;.  interface|
	00000310  4e 61 6d 65 50 72 65 66  69 78 3a 20 22 22 0a 64  |NamePrefix: &quot;&quot;.d|
	00000320  65 74 65 63 74 4c 6f 63  61 6c 4d 6f 64 65 3a 20  |etectLocalMode: |
	00000330  22 22 0a 65 6e 61 62 6c  65 50 72 6f 66 69 6c 69  |&quot;&quot;.enableProfili|
	00000340  6e 67 3a 20 66 61 6c 73  65 0a 68 65 61 6c 74 68  |ng: false.health|
	00000350  7a 42 69 6e 64 41 64 64  72 65 73 73 3a 20 22 22  |zBindAddress: &quot;&quot;|
	00000360  0a 68 6f 73 74 6e 61 6d  65 4f 76 65 72 72 69 64  |.hostnameOverrid|
	00000370  65 3a 20 22 22 0a 69 70  74 61 62 6c 65 73 3a 0a  |e: &quot;&quot;.iptables:.|
	00000380  20 20 6c 6f 63 61 6c 68  6f 73 74 4e 6f 64 65 50  |  localhostNodeP|
	00000390  6f 72 74 73 3a 20 6e 75  6c 6c 0a 20 20 6d 61 73  |orts: null.  mas|
	000003a0  71 75 65 72 61 64 65 41  6c 6c 3a 20 66 61 6c 73  |queradeAll: fals|
	000003b0  65 0a 20 20 6d 61 73 71  75 65 72 61 64 65 42 69  |e.  masqueradeBi|
	000003c0  74 3a 20 6e 75 6c 6c 0a  20 20 6d 69 6e 53 79 6e  |t: null.  minSyn|
	000003d0  63 50 65 72 69 6f 64 3a  20 31 73 0a 20 20 73 79  |cPeriod: 1s.  sy|
	000003e0  6e 63 50 65 72 69 6f 64  3a 20 30 73 0a 69 70 76  |ncPeriod: 0s.ipv|
	000003f0  73 3a 0a 20 20 65 78 63  6c 75 64 65 43 49 44 52  |s:.  excludeCIDR|
	00000400  73 3a 20 6e 75 6c 6c 0a  20 20 6d 69 6e 53 79 6e  |s: null.  minSyn|
	00000410  63 50 65 72 69 6f 64 3a  20 30 73 0a 20 20 73 63  |cPeriod: 0s.  sc|
	00000420  68 65 64 75 6c 65 72 3a  20 22 22 0a 20 20 73 74  |heduler: &quot;&quot;.  st|
	00000430  72 69 63 74 41 52 50 3a  20 66 61 6c 73 65 0a 20  |rictARP: false. |
	00000440  20 73 79 6e 63 50 65 72  69 6f 64 3a 20 30 73 0a  | syncPeriod: 0s.|
	00000450  20 20 74 63 70 46 69 6e  54 69 6d 65 6f 75 74 3a  |  tcpFinTimeout:|
	00000460  20 30 73 0a 20 20 74 63  70 54 69 6d 65 6f 75 74  | 0s.  tcpTimeout|
	00000470  3a 20 30 73 0a 20 20 75  64 70 54 69 6d 65 6f 75  |: 0s.  udpTimeou|
	00000480  74 3a 20 30 73 0a 6b 69  6e 64 3a 20 4b 75 62 65  |t: 0s.kind: Kube|
	00000490  50 72 6f 78 79 43 6f 6e  66 69 67 75 72 61 74 69  |ProxyConfigurati|
	000004a0  6f 6e 0a 6c 6f 67 67 69  6e 67 3a 0a 20 20 66 6c  |on.logging:.  fl|
	000004b0  75 73 68 46 72 65 71 75  65 6e 63 79 3a 20 30 0a  |ushFrequency: 0.|
	000004c0  20 20 6f 70 74 69 6f 6e  73 3a 0a 20 20 20 20 6a  |  options:.    j|
	000004d0  73 6f 6e 3a 0a 20 20 20  20 20 20 69 6e 66 6f 42  |son:.      infoB|
	000004e0  75 66 66 65 72 53 69 7a  65 3a 20 22 30 22 0a 20  |ufferSize: &quot;0&quot;. |
	000004f0  20 20 20 74 65 78 74 3a  0a 20 20 20 20 20 20 69  |   text:.      i|
	00000500  6e 66 6f 42 75 66 66 65  72 53 69 7a 65 3a 20 22  |nfoBufferSize: &quot;|
	00000510  30 22 0a 20 20 76 65 72  62 6f 73 69 74 79 3a 20  |0&quot;.  verbosity: |
	00000520  30 0a 6d 65 74 72 69 63  73 42 69 6e 64 41 64 64  |0.metricsBindAdd|
	00000530  72 65 73 73 3a 20 22 22  0a 6d 6f 64 65 3a 20 69  |ress: &quot;&quot;.mode: i|
	00000540  70 74 61 62 6c 65 73 0a  6e 66 74 61 62 6c 65 73  |ptables.nftables|
	00000550  3a 0a 20 20 6d 61 73 71  75 65 72 61 64 65 41 6c  |:.  masqueradeAl|
	00000560  6c 3a 20 66 61 6c 73 65  0a 20 20 6d 61 73 71 75  |l: false.  masqu|
	00000570  65 72 61 64 65 42 69 74  3a 20 6e 75 6c 6c 0a 20  |eradeBit: null. |
	00000580  20 6d 69 6e 53 79 6e 63  50 65 72 69 6f 64 3a 20  | minSyncPeriod: |
	00000590  30 73 0a 20 20 73 79 6e  63 50 65 72 69 6f 64 3a  |0s.  syncPeriod:|
	000005a0  20 30 73 0a 6e 6f 64 65  50 6f 72 74 41 64 64 72  | 0s.nodePortAddr|
	000005b0  65 73 73 65 73 3a 20 6e  75 6c 6c 0a 6f 6f 6d 53  |esses: null.oomS|
	000005c0  63 6f 72 65 41 64 6a 3a  20 6e 75 6c 6c 0a 70 6f  |coreAdj: null.po|
	000005d0  72 74 52 61 6e 67 65 3a  20 22 22 0a 73 68 6f 77  |rtRange: &quot;&quot;.show|
	000005e0  48 69 64 64 65 6e 4d 65  74 72 69 63 73 46 6f 72  |HiddenMetricsFor|
	000005f0  56 65 72 73 69 6f 6e 3a  20 22 22 0a 77 69 6e 6b  |Version: &quot;&quot;.wink|
	00000600  65 72 6e 65 6c 3a 0a 20  20 65 6e 61 62 6c 65 44  |ernel:.  enableD|
	00000610  53 52 3a 20 66 61 6c 73  65 0a 20 20 66 6f 72 77  |SR: false.  forw|
	00000620  61 72 64 48 65 61 6c 74  68 43 68 65 63 6b 56 69  |ardHealthCheckVi|
	00000630  70 3a 20 66 61 6c 73 65  0a 20 20 6e 65 74 77 6f  |p: false.  netwo|
	00000640  72 6b 4e 61 6d 65 3a 20  22 22 0a 20 20 72 6f 6f  |rkName: &quot;&quot;.  roo|
	00000650  74 48 6e 73 45 6e 64 70  6f 69 6e 74 4e 61 6d 65  |tHnsEndpointName|
	00000660  3a 20 22 22 0a 20 20 73  6f 75 72 63 65 56 69 70  |: &quot;&quot;.  sourceVip|
	00000670  3a 20 22 22 12 ae 03 0a  0f 6b 75 62 65 63 6f 6e  |: &quot;&quot;.....kubecon|
	00000680  66 69 67 2e 63 6f 6e 66  12 9a 03 61 70 69 56 65  |fig.conf...apiVe|
	00000690  72 73 69 6f 6e 3a 20 76  31 0a 6b 69 6e 64 3a 20  |rsion: v1.kind: |
	000006a0  43 6f 6e 66 69 67 0a 63  6c 75 73 74 65 72 73 3a  |Config.clusters:|
	000006b0  0a 2d 20 63 6c 75 73 74  65 72 3a 0a 20 20 20 20  |.- cluster:.    |
	000006c0  63 65 72 74 69 66 69 63  61 74 65 2d 61 75 74 68  |certificate-auth|
	000006d0  6f 72 69 74 79 3a 20 2f  76 61 72 2f 72 75 6e 2f  |ority: /var/run/|
	000006e0  73 65 63 72 65 74 73 2f  6b 75 62 65 72 6e 65 74  |secrets/kubernet|
	000006f0  65 73 2e 69 6f 2f 73 65  72 76 69 63 65 61 63 63  |es.io/serviceacc|
	00000700  6f 75 6e 74 2f 63 61 2e  63 72 74 0a 20 20 20 20  |ount/ca.crt.    |
	00000710  73 65 72 76 65 72 3a 20  68 74 74 70 73 3a 2f 2f  |server: https://|
	00000720  6b 69 6e 64 2d 63 6f 6e  74 72 6f 6c 2d 70 6c 61  |kind-control-pla|
	00000730  6e 65 3a 36 34 34 33 0a  20 20 6e 61 6d 65 3a 20  |ne:6443.  name: |
	00000740  64 65 66 61 75 6c 74 0a  63 6f 6e 74 65 78 74 73  |default.contexts|
	00000750  3a 0a 2d 20 63 6f 6e 74  65 78 74 3a 0a 20 20 20  |:.- context:.   |
	00000760  20 63 6c 75 73 74 65 72  3a 20 64 65 66 61 75 6c  | cluster: defaul|
	00000770  74 0a 20 20 20 20 6e 61  6d 65 73 70 61 63 65 3a  |t.    namespace:|
	00000780  20 64 65 66 61 75 6c 74  0a 20 20 20 20 75 73 65  | default.    use|
	00000790  72 3a 20 64 65 66 61 75  6c 74 0a 20 20 6e 61 6d  |r: default.  nam|
	000007a0  65 3a 20 64 65 66 61 75  6c 74 0a 63 75 72 72 65  |e: default.curre|
	000007b0  6e 74 2d 63 6f 6e 74 65  78 74 3a 20 64 65 66 61  |nt-context: defa|
	000007c0  75 6c 74 0a 75 73 65 72  73 3a 0a 2d 20 6e 61 6d  |ult.users:.- nam|
	000007d0  65 3a 20 64 65 66 61 75  6c 74 0a 20 20 75 73 65  |e: default.  use|
	000007e0  72 3a 0a 20 20 20 20 74  6f 6b 65 6e 46 69 6c 65  |r:.    tokenFile|
	000007f0  3a 20 2f 76 61 72 2f 72  75 6e 2f 73 65 63 72 65  |: /var/run/secre|
	00000800  74 73 2f 6b 75 62 65 72  6e 65 74 65 73 2e 69 6f  |ts/kubernetes.io|
	00000810  2f 73 65 72 76 69 63 65  61 63 63 6f 75 [truncated 102 chars]
 &amp;gt;
I1215 14:50:15.319974     230 kubelet.go:73] attempting to download the KubeletConfiguration from ConfigMap &quot;kubelet-config&quot;
I1215 14:50:15.320052     230 type.go:165] &quot;Request Body&quot; body=&quot;&quot;
I1215 14:50:15.320143     230 round_trippers.go:527] &quot;Request&quot; curlCommand=&amp;lt;
	curl -v -XGET  -H &quot;Accept: application/vnd.kubernetes.protobuf,application/json&quot; -H &quot;User-Agent: kubeadm/v1.35.0 (linux/amd64) kubernetes/f35f950&quot; -H &quot;Authorization: Bearer &amp;lt;masked&amp;gt;&quot; '&lt;/span&gt;https://kind-control-plane:6443/api/v1/namespaces/kube-system/configmaps/kubelet-config?timeout&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;10s&lt;span class=&quot;s1&quot;&gt;'
 &amp;gt;
I1215 14:50:15.322275     230 round_trippers.go:632] &quot;Response&quot; verb=&quot;GET&quot; url=&quot;https://kind-control-plane:6443/api/v1/namespaces/kube-system/configmaps/kubelet-config?timeout=10s&quot; status=&quot;200 OK&quot; headers=&amp;lt;
	Audit-Id: edacaa09-2a92-49f8-992d-467253d02bac
	Cache-Control: no-cache, private
	Content-Length: 1453
	Content-Type: application/vnd.kubernetes.protobuf
	Date: Mon, 15 Dec 2025 14:50:15 GMT
	X-Kubernetes-Pf-Flowschema-Uid: f54c5d84-c2d8-4cbb-8801-07adb48ce73d
	X-Kubernetes-Pf-Prioritylevel-Uid: 7df0c0a7-2f8a-40ca-9625-0b6635feccd2
 &amp;gt; milliseconds=2 getConnectionMilliseconds=0 serverProcessingMilliseconds=1
I1215 14:50:15.322454     230 type.go:165] &quot;Response Body&quot; body=&amp;lt;
	00000000  6b 38 73 00 0a 0f 0a 02  76 31 12 09 43 6f 6e 66  |k8s.....v1..Conf|
	00000010  69 67 4d 61 70 12 91 0b  0a ac 01 0a 0e 6b 75 62  |igMap........kub|
	00000020  65 6c 65 74 2d 63 6f 6e  66 69 67 12 00 1a 0b 6b  |elet-config....k|
	00000030  75 62 65 2d 73 79 73 74  65 6d 22 00 2a 24 30 32  |ube-system&quot;.*$02|
	00000040  36 61 32 32 32 63 2d 39  66 65 34 2d 34 35 39 37  |6a222c-9fe4-4597|
	00000050  2d 39 30 38 61 2d 62 35  65 35 64 62 33 35 32 35  |-908a-b5e5db3525|
	00000060  36 64 32 03 32 31 30 38  00 42 08 08 d7 da ff c9  |6d2.2108.B......|
	00000070  06 10 00 8a 01 51 0a 07  6b 75 62 65 61 64 6d 12  |.....Q..kubeadm.|
	00000080  06 55 70 64 61 74 65 1a  02 76 31 22 08 08 d7 da  |.Update..v1&quot;....|
	00000090  ff c9 06 10 00 32 08 46  69 65 6c 64 73 56 31 3a  |.....2.FieldsV1:|
	000000a0  24 0a 22 7b 22 66 3a 64  61 74 61 22 3a 7b 22 2e  |$.&quot;{&quot;f:data&quot;:{&quot;.|
	000000b0  22 3a 7b 7d 2c 22 66 3a  6b 75 62 65 6c 65 74 22  |&quot;:{},&quot;f:kubelet&quot;|
	000000c0  3a 7b 7d 7d 7d 42 00 12  df 09 0a 07 6b 75 62 65  |:{}}}B......kube|
	000000d0  6c 65 74 12 d3 09 61 70  69 56 65 72 73 69 6f 6e  |let...apiVersion|
	000000e0  3a 20 6b 75 62 65 6c 65  74 2e 63 6f 6e 66 69 67  |: kubelet.config|
	000000f0  2e 6b 38 73 2e 69 6f 2f  76 31 62 65 74 61 31 0a  |.k8s.io/v1beta1.|
	00000100  61 75 74 68 65 6e 74 69  63 61 74 69 6f 6e 3a 0a  |authentication:.|
	00000110  20 20 61 6e 6f 6e 79 6d  6f 75 73 3a 0a 20 20 20  |  anonymous:.   |
	00000120  20 65 6e 61 62 6c 65 64  3a 20 66 61 6c 73 65 0a  | enabled: false.|
	00000130  20 20 77 65 62 68 6f 6f  6b 3a 0a 20 20 20 20 63  |  webhook:.    c|
	00000140  61 63 68 65 54 54 4c 3a  20 30 73 0a 20 20 20 20  |acheTTL: 0s.    |
	00000150  65 6e 61 62 6c 65 64 3a  20 74 72 75 65 0a 20 20  |enabled: true.  |
	00000160  78 35 30 39 3a 0a 20 20  20 20 63 6c 69 65 6e 74  |x509:.    client|
	00000170  43 41 46 69 6c 65 3a 20  2f 65 74 63 2f 6b 75 62  |CAFile: /etc/kub|
	00000180  65 72 6e 65 74 65 73 2f  70 6b 69 2f 63 61 2e 63  |ernetes/pki/ca.c|
	00000190  72 74 0a 61 75 74 68 6f  72 69 7a 61 74 69 6f 6e  |rt.authorization|
	000001a0  3a 0a 20 20 6d 6f 64 65  3a 20 57 65 62 68 6f 6f  |:.  mode: Webhoo|
	000001b0  6b 0a 20 20 77 65 62 68  6f 6f 6b 3a 0a 20 20 20  |k.  webhook:.   |
	000001c0  20 63 61 63 68 65 41 75  74 68 6f 72 69 7a 65 64  | cacheAuthorized|
	000001d0  54 54 4c 3a 20 30 73 0a  20 20 20 20 63 61 63 68  |TTL: 0s.    cach|
	000001e0  65 55 6e 61 75 74 68 6f  72 69 7a 65 64 54 54 4c  |eUnauthorizedTTL|
	000001f0  3a 20 30 73 0a 63 67 72  6f 75 70 44 72 69 76 65  |: 0s.cgroupDrive|
	00000200  72 3a 20 73 79 73 74 65  6d 64 0a 63 67 72 6f 75  |r: systemd.cgrou|
	00000210  70 52 6f 6f 74 3a 20 2f  6b 75 62 65 6c 65 74 0a  |pRoot: /kubelet.|
	00000220  63 6c 75 73 74 65 72 44  4e 53 3a 0a 2d 20 31 30  |clusterDNS:.- 10|
	00000230  2e 39 36 2e 30 2e 31 30  0a 63 6c 75 73 74 65 72  |.96.0.10.cluster|
	00000240  44 6f 6d 61 69 6e 3a 20  63 6c 75 73 74 65 72 2e  |Domain: cluster.|
	00000250  6c 6f 63 61 6c 0a 63 6f  6e 74 61 69 6e 65 72 52  |local.containerR|
	00000260  75 6e 74 69 6d 65 45 6e  64 70 6f 69 6e 74 3a 20  |untimeEndpoint: |
	00000270  22 22 0a 63 70 75 4d 61  6e 61 67 65 72 52 65 63  |&quot;&quot;.cpuManagerRec|
	00000280  6f 6e 63 69 6c 65 50 65  72 69 6f 64 3a 20 30 73  |oncilePeriod: 0s|
	00000290  0a 63 72 61 73 68 4c 6f  6f 70 42 61 63 6b 4f 66  |.crashLoopBackOf|
	000002a0  66 3a 20 7b 7d 0a 65 76  69 63 74 69 6f 6e 48 61  |f: {}.evictionHa|
	000002b0  72 64 3a 0a 20 20 69 6d  61 67 65 66 73 2e 61 76  |rd:.  imagefs.av|
	000002c0  61 69 6c 61 62 6c 65 3a  20 30 25 0a 20 20 6e 6f  |ailable: 0%.  no|
	000002d0  64 65 66 73 2e 61 76 61  69 6c 61 62 6c 65 3a 20  |defs.available: |
	000002e0  30 25 0a 20 20 6e 6f 64  65 66 73 2e 69 6e 6f 64  |0%.  nodefs.inod|
	000002f0  65 73 46 72 65 65 3a 20  30 25 0a 65 76 69 63 74  |esFree: 0%.evict|
	00000300  69 6f 6e 50 72 65 73 73  75 72 65 54 72 61 6e 73  |ionPressureTrans|
	00000310  69 74 69 6f 6e 50 65 72  69 6f 64 3a 20 30 73 0a  |itionPeriod: 0s.|
	00000320  66 61 69 6c 53 77 61 70  4f 6e 3a 20 66 61 6c 73  |failSwapOn: fals|
	00000330  65 0a 66 69 6c 65 43 68  65 63 6b 46 72 65 71 75  |e.fileCheckFrequ|
	00000340  65 6e 63 79 3a 20 30 73  0a 68 65 61 6c 74 68 7a  |ency: 0s.healthz|
	00000350  42 69 6e 64 41 64 64 72  65 73 73 3a 20 31 32 37  |BindAddress: 127|
	00000360  2e 30 2e 30 2e 31 0a 68  65 61 6c 74 68 7a 50 6f  |.0.0.1.healthzPo|
	00000370  72 74 3a 20 31 30 32 34  38 0a 68 74 74 70 43 68  |rt: 10248.httpCh|
	00000380  65 63 6b 46 72 65 71 75  65 6e 63 79 3a 20 30 73  |eckFrequency: 0s|
	00000390  0a 69 6d 61 67 65 47 43  48 69 67 68 54 68 72 65  |.imageGCHighThre|
	000003a0  73 68 6f 6c 64 50 65 72  63 65 6e 74 3a 20 31 30  |sholdPercent: 10|
	000003b0  30 0a 69 6d 61 67 65 4d  61 78 69 6d 75 6d 47 43  |0.imageMaximumGC|
	000003c0  41 67 65 3a 20 30 73 0a  69 6d 61 67 65 4d 69 6e  |Age: 0s.imageMin|
	000003d0  69 6d 75 6d 47 43 41 67  65 3a 20 30 73 0a 6b 69  |imumGCAge: 0s.ki|
	000003e0  6e 64 3a 20 4b 75 62 65  6c 65 74 43 6f 6e 66 69  |nd: KubeletConfi|
	000003f0  67 75 72 61 74 69 6f 6e  0a 6c 6f 67 67 69 6e 67  |guration.logging|
	00000400  3a 0a 20 20 66 6c 75 73  68 46 72 65 71 75 65 6e  |:.  flushFrequen|
	00000410  63 79 3a 20 30 0a 20 20  6f 70 74 69 6f 6e 73 3a  |cy: 0.  options:|
	00000420  0a 20 20 20 20 6a 73 6f  6e 3a 0a 20 20 20 20 20  |.    json:.     |
	00000430  20 69 6e 66 6f 42 75 66  66 65 72 53 69 7a 65 3a  | infoBufferSize:|
	00000440  20 22 30 22 0a 20 20 20  20 74 65 78 74 3a 0a 20  | &quot;0&quot;.    text:. |
	00000450  20 20 20 20 20 69 6e 66  6f 42 75 66 66 65 72 53  |     infoBufferS|
	00000460  69 7a 65 3a 20 22 30 22  0a 20 20 76 65 72 62 6f  |ize: &quot;0&quot;.  verbo|
	00000470  73 69 74 79 3a 20 30 0a  6d 65 6d 6f 72 79 53 77  |sity: 0.memorySw|
	00000480  61 70 3a 20 7b 7d 0a 6e  6f 64 65 53 74 61 74 75  |ap: {}.nodeStatu|
	00000490  73 52 65 70 6f 72 74 46  72 65 71 75 65 6e 63 79  |sReportFrequency|
	000004a0  3a 20 30 73 0a 6e 6f 64  65 53 74 61 74 75 73 55  |: 0s.nodeStatusU|
	000004b0  70 64 61 74 65 46 72 65  71 75 65 6e 63 79 3a 20  |pdateFrequency: |
	000004c0  30 73 0a 72 6f 74 61 74  65 43 65 72 74 69 66 69  |0s.rotateCertifi|
	000004d0  63 61 74 65 73 3a 20 74  72 75 65 0a 72 75 6e 74  |cates: true.runt|
	000004e0  69 6d 65 52 65 71 75 65  73 74 54 69 6d 65 6f 75  |imeRequestTimeou|
	000004f0  74 3a 20 30 73 0a 73 68  75 74 64 6f 77 6e 47 72  |t: 0s.shutdownGr|
	00000500  61 63 65 50 65 72 69 6f  64 3a 20 30 73 0a 73 68  |acePeriod: 0s.sh|
	00000510  75 74 64 6f 77 6e 47 72  61 63 65 50 65 72 69 6f  |utdownGracePerio|
	00000520  64 43 72 69 74 69 63 61  6c 50 6f 64 73 3a 20 30  |dCriticalPods: 0|
	00000530  73 0a 73 74 61 74 69 63  50 6f 64 50 61 74 68 3a  |s.staticPodPath:|
	00000540  20 2f 65 74 63 2f 6b 75  62 65 72 6e 65 74 65 73  | /etc/kubernetes|
	00000550  2f 6d 61 6e 69 66 65 73  74 73 0a 73 74 72 65 61  |/manifests.strea|
	00000560  6d 69 6e 67 43 6f 6e 6e  65 63 74 69 6f 6e 49 64  |mingConnectionId|
	00000570  6c 65 54 69 6d 65 6f 75  74 3a 20 30 73 0a 73 79  |leTimeout: 0s.sy|
	00000580  6e 63 46 72 65 71 75 65  6e 63 79 3a 20 30 73 0a  |ncFrequency: 0s.|
	00000590  76 6f 6c 75 6d 65 53 74  61 74 73 41 67 67 50 65  |volumeStatsAggPe|
	000005a0  72 69 6f 64 3a 20 30 73  0a 1a 00 22 00           |riod: 0s...&quot;.|
 &amp;gt;
I1215 14:50:15.324583     230 initconfiguration.go:114] skip CRI socket detection, fill with the default CRI socket unix:///var/run/containerd/containerd.sock
I1215 14:50:15.324815     230 interface.go:432] Looking for default routes with IPv4 addresses
I1215 14:50:15.324830     230 interface.go:437] Default route transits interface &quot;eth0&quot;
I1215 14:50:15.324975     230 interface.go:209] Interface eth0 is up
I1215 14:50:15.325021     230 interface.go:257] Interface &quot;eth0&quot; has 3 addresses :[172.18.0.3/16 fc00:****::3/64 fe80::****/64].
I1215 14:50:15.325041     230 interface.go:224] Checking addr  172.18.0.3/16.
I1215 14:50:15.325057     230 interface.go:231] IP found 172.18.0.3
I1215 14:50:15.325072     230 interface.go:263] Found valid IPv4 address 172.18.0.3 for interface &quot;eth0&quot;.
I1215 14:50:15.325085     230 interface.go:443] Found active IP 172.18.0.3 
I1215 14:50:15.325133     230 common.go:148] WARNING: tolerating control plane version v1.34.0 as a pre-release version
I1215 14:50:15.325168     230 preflight.go:108] [preflight] Running configuration dependant checks
I1215 14:50:15.325179     230 controlplaneprepare.go:225] [download-certs] Skipping certs download
I1215 14:50:15.325485     230 kubelet.go:147] [kubelet-start] writing bootstrap kubelet config file at /etc/kubernetes/bootstrap-kubelet.conf
I1215 14:50:15.327017     230 kubelet.go:162] [kubelet-start] writing CA certificate at /etc/kubernetes/pki/ca.crt
I1215 14:50:15.327125     230 kubelet.go:178] [kubelet-start] Checking for an existing Node in the cluster with name &quot;5a5adbbfec7a&quot; and status &quot;Ready&quot;
I1215 14:50:15.327178     230 type.go:165] &quot;Request Body&quot; body=&quot;&quot;
I1215 14:50:15.327263     230 round_trippers.go:527] &quot;Request&quot; curlCommand=&amp;lt;
	curl -v -XGET  -H &quot;Accept: application/vnd.kubernetes.protobuf,application/json&quot; -H &quot;User-Agent: kubeadm/v1.35.0 (linux/amd64) kubernetes/f35f950&quot; -H &quot;Authorization: Bearer &amp;lt;masked&amp;gt;&quot; '&lt;/span&gt;https://kind-control-plane:6443/api/v1/nodes/5a5adbbfec7a?timeout&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;10s&lt;span class=&quot;s1&quot;&gt;'
 &amp;gt;
I1215 14:50:15.329075     230 round_trippers.go:632] &quot;Response&quot; verb=&quot;GET&quot; url=&quot;https://kind-control-plane:6443/api/v1/nodes/5a5adbbfec7a?timeout=10s&quot; status=&quot;404 Not Found&quot; headers=&amp;lt;
	Audit-Id: b5dddad2-5b97-4e03-9241-52b266d62df5
	Cache-Control: no-cache, private
	Content-Length: 115
	Content-Type: application/vnd.kubernetes.protobuf
	Date: Mon, 15 Dec 2025 14:50:15 GMT
	X-Kubernetes-Pf-Flowschema-Uid: f54c5d84-c2d8-4cbb-8801-07adb48ce73d
	X-Kubernetes-Pf-Prioritylevel-Uid: 7df0c0a7-2f8a-40ca-9625-0b6635feccd2
 &amp;gt; milliseconds=1 getConnectionMilliseconds=0 serverProcessingMilliseconds=1
I1215 14:50:15.329149     230 type.go:165] &quot;Response Body&quot; body=&amp;lt;
	00000000  6b 38 73 00 0a 0c 0a 02  76 31 12 06 53 74 61 74  |k8s.....v1..Stat|
	00000010  75 73 12 5b 0a 06 0a 00  12 00 1a 00 12 07 46 61  |us.[..........Fa|
	00000020  69 6c 75 72 65 1a 1e 6e  6f 64 65 73 20 22 35 61  |ilure..nodes &quot;5a|
	00000030  35 61 64 62 62 66 65 63  37 61 22 20 6e 6f 74 20  |5adbbfec7a&quot; not |
	00000040  66 6f 75 6e 64 22 08 4e  6f 74 46 6f 75 6e 64 2a  |found&quot;.NotFound*|
	00000050  1b 0a 0c 35 61 35 61 64  62 62 66 65 63 37 61 12  |...5a5adbbfec7a.|
	00000060  00 1a 05 6e 6f 64 65 73  28 00 32 00 30 94 03 1a  |...nodes(.2.0...|
	00000070  00 22 00                                          |.&quot;.|
 &amp;gt;
I1215 14:50:15.329251     230 kubelet.go:193] [kubelet-start] Stopping the kubelet
[kubelet-start] Writing kubelet configuration to file &quot;/var/lib/kubelet/instance-config.yaml&quot;
[patches] Applied patch of type &quot;application/strategic-merge-patch+json&quot; to target &quot;kubeletconfiguration&quot;
[kubelet-start] Writing kubelet configuration to file &quot;/var/lib/kubelet/config.yaml&quot;
[kubelet-start] Writing kubelet environment file with flags to file &quot;/var/lib/kubelet/kubeadm-flags.env&quot;
[kubelet-start] Starting the kubelet
[kubelet-check] Waiting for a healthy kubelet at http://127.0.0.1:10248/healthz. This can take up to 4m0s
[kubelet-check] The kubelet is healthy after 501.664771ms
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap
I1215 14:50:15.990092     230 loader.go:405] Config loaded from file:  /etc/kubernetes/kubelet.conf
I1215 14:50:15.990751     230 cert_rotation.go:141] &quot;Starting client certificate rotation controller&quot; logger=&quot;tls-transport-cache&quot;
I1215 14:50:15.991227     230 loader.go:405] Config loaded from file:  /etc/kubernetes/kubelet.conf

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run '&lt;/span&gt;kubectl get nodes&lt;span class=&quot;s1&quot;&gt;' on the control-plane to see this node join the cluster.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

&lt;/details&gt;

&lt;p&gt;So, at this point now.&lt;br /&gt;
We’ve answered our second question also. &lt;br /&gt;
i.e, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;can I try to create a kubeadm token manually and use that to join an existing Kubernetes cluster successfully?&lt;/code&gt;.&lt;br /&gt;
Yes, I can! We saw it above!&lt;/p&gt;

&lt;p&gt;But wait, what next now?&lt;/p&gt;

&lt;p&gt;We saw the following bit in our output:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;This node has joined the cluster:
&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; Certificate signing request was sent to apiserver and a response was received.
&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; The Kubelet was informed of the new secure connection details.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I have more questions now.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;What is the “Certificate signing request”? And what “response” we received?&lt;/li&gt;
  &lt;li&gt;The Kubelet was informed of the new secure connection details. How?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s try to answer them now.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;q-what-is-the-certificate-signing-request-and-what-response-we-received&quot;&gt;Q: What is the “Certificate signing request”? And what “response” we received?&lt;/h3&gt;

&lt;p&gt;So, back to the control-plane node, let’s check the following:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ kubectl get certificatesigningrequest &lt;span class=&quot;nt&quot;&gt;-A&lt;/span&gt;

NAME        AGE     SIGNERNAME                                    REQUESTOR                        REQUESTEDDURATION   CONDITION
csr-c5j6z   7m46s   kubernetes.io/kube-apiserver-client-kubelet   system:bootstrap:pqrstu          &amp;lt;none&amp;gt;              Approved,Issued
csr-qzbvk   112m    kubernetes.io/kube-apiserver-client-kubelet   system:node:kind-control-plane   &amp;lt;none&amp;gt;              Approved,Issued
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;OK, so, we see two &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CertificateSigningRequest&lt;/code&gt; (CSR) objects.&lt;br /&gt;
One of them was requested by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system:node:kind-control-plane&lt;/code&gt; user (our kind-control-plane node).&lt;br /&gt;
And the other one was requested by us, through the user &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system:bootstrap:pqrstu&lt;/code&gt; from the docker container node (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;joining-node&lt;/code&gt;).&lt;br /&gt;
And both are in condition &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Approved&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Issued&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let’s also see the body of the CSR object created by our request.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;❯ kubectl get certificatesigningrequest csr-c5j6z -o yaml&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;apiVersion&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;certificates.k8s.io/v1&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;CertificateSigningRequest&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;metadata&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;spec&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;system:bootstrappers&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;system:authenticated&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;LS0tLS1CRUdJTi****LS0K&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;signerName&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;kubernetes.io/kube-apiserver-client-kubelet&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;usages&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;digital signature&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;client auth&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;system:bootstrap:pqrstu&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;certificate&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;LS0tLS1CRUdJTiBDR****LS0K&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;conditions&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Auto approving kubelet client certificate after SubjectAccessReview.&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;reason&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;AutoApproved&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;True&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Approved&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;From the object definition, I understand that the user &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system:bootstrap:pqrstu&lt;/code&gt;, made this CSR request for purposes, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;usages: {digital signature, client auth}&lt;/code&gt;.&lt;br /&gt;
And that is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AutoApproved&lt;/code&gt; (after some process called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SubjectAccessReview&lt;/code&gt; which I am not exploring in this blog, but I know that is important).&lt;/p&gt;

&lt;p&gt;Nice. But what did we receive as response?&lt;/p&gt;

&lt;p&gt;I see, we got back a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;certificate&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Approved&lt;/code&gt; (with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;status: &quot;True&quot;&lt;/code&gt;) in the CSR object’s status section. &lt;br /&gt;
So, that means the response we got back is the CSR getting approved. (maybe, I’m still not 100% sure about which response we’re talking).&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;q-the-kubelet-was-informed-of-the-new-secure-connection-details-how&quot;&gt;Q: The Kubelet was informed of the new secure connection details. How?&lt;/h3&gt;

&lt;p&gt;I do see some relevant logs (truncated to just show the relevant bits):&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;kubelet-start] writing CA certificate at /etc/kubernetes/pki/ca.crt

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;kubelet-start] Writing kubelet configuration to file &lt;span class=&quot;s2&quot;&gt;&quot;/var/lib/kubelet/config.yaml&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s check if we see anything new inside our docker container node we joined from (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;joining-node&lt;/code&gt;).&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@83ab08acf723:/# tree /etc/kubernetes/
/etc/kubernetes/
|-- kubelet.conf
|-- manifests
&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; pki
    &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; ca.crt

3 directories, 2 files
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We do.&lt;br /&gt;
We now have a new directory called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etcd/kubernetes/&lt;/code&gt; which contains a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubelet.conf&lt;/code&gt; file as well as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pki/ca.crt&lt;/code&gt;.&lt;br /&gt;
(same as what the logs pointed us.)&lt;/p&gt;

&lt;p&gt;Let’s see the contents of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubelet.conf&lt;/code&gt; file:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;root@0ecd1b55abc8:/# cat /etc/kubernetes/kubelet.conf&lt;/span&gt; 

&lt;span class=&quot;na&quot;&gt;apiVersion&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;v1&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;clusters&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;cluster&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;certificate-authority-data&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;LS0tLS1CRUd****LS0tLS0K&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;https://kind-control-plane:6443&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;default-cluster&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;contexts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;cluster&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;default-cluster&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;default&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;default-auth&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;default-context&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;current-context&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;default-context&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Config&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;default-auth&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;client-certificate&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/var/lib/kubelet/pki/kubelet-client-current.pem&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;client-key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/var/lib/kubelet/pki/kubelet-client-current.pem&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;certificate-authority-data&lt;/code&gt; field stores the public certificate of Cluster’s CA (Which is coming from the control-plane of the cluster).&lt;br /&gt;
If you decode the value (using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;echo &quot;LS0tLS1CRUd****LS0tLS0K&quot; | base64 -d&lt;/code&gt;, it will match the contents of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/kubernetes/pki/ca.crt&lt;/code&gt; on the kind-control-plane node.&lt;/p&gt;

&lt;p&gt;We also see the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubelet.conf&lt;/code&gt; file points to the location of the kubelet’s certificates &amp;amp; keys - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/lib/kubelet/pki/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As I understand (from reading docs):&lt;/p&gt;

&lt;p&gt;The kubelet generates its own certificates/keys locally (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/lib/kubelet/pki/Kubelet.crt | .key&lt;/code&gt;) and then send a CSR (Certificate Signing Request) to the API Server.&lt;br /&gt;
The control-plane (controller-manager?) then sign that CSR using the cluster CA keys (which we see from the field - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;certificate-authority-data&lt;/code&gt;).&lt;br /&gt;
And then signed certificate is written into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubelet.conf&lt;/code&gt; (to be precise here - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/lib/kubelet/pki/kubelet-client-current.pem&lt;/code&gt;, which comes from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;status.certificate:&lt;/code&gt; field of the CSR Object).&lt;/p&gt;

&lt;p&gt;The full tree of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/lib/kubelet/pki/&lt;/code&gt; looks like:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@fd5e81a7604b:/# tree /var/lib/kubelet/pki/
/var/lib/kubelet/pki/
|-- kubelet-client-2025-12-16-07-35-31.pem
|-- kubelet-client-current.pem -&amp;gt; /var/lib/kubelet/pki/kubelet-client-2025-12-16-07-35-31.pem
|-- kubelet.crt
&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; kubelet.key

1 directory, 4 files
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(&lt;strong&gt;Note:&lt;/strong&gt; The part, “&lt;em&gt;kubelet generate a private key and a CSR for submission to a cluster-level certificate signing process&lt;/em&gt;” was originally proposed as part of this design proposal - &lt;a href=&quot;https://github.com/kubernetes/design-proposals-archive/blob/main/cluster-lifecycle/kubelet-tls-bootstrap.md&quot;&gt;Kubelet TLS bootstrap&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;So, after this point onwards, our (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;joining-node&lt;/code&gt;) node aka the Kubelet has its own set of signed certificates.&lt;br /&gt;
And so, the kubeadm bearer token is no longer required.&lt;br /&gt;
And all further interactions with the control-plane will use these certificates via mTLS (mutual TLS).&lt;/p&gt;

&lt;p&gt;Also, note that - not just certificates, a lot more, was also added to the filesystem of the (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;joining-node&lt;/code&gt;) node.&lt;br /&gt;
I don’t understand details about every single listed item, but here’s the full tree:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;root@0ecd1b55abc8:/# tree /var/lib/kubelet/
/var/lib/kubelet/
|-- allocated_pods_state
|-- checkpoints
|-- config.yaml
|-- cpu_manager_state
|-- device-plugins
|   &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; kubelet.sock
|-- dra_manager_state
|-- instance-config.yaml
|-- kubeadm-flags.env
|-- memory_manager_state
|-- pki
|   |-- kubelet-client-2025-12-16-10-18-54.pem
|   |-- kubelet-client-current.pem -&amp;gt; /var/lib/kubelet/pki/kubelet-client-2025-12-16-10-18-54.pem
|   |-- kubelet.crt
|   &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; kubelet.key
|-- plugins
|-- plugins_registry
|-- pod-resources
|   &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; kubelet.sock
&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; pods
    |-- 4683e97e-5735-459f-b965-24a5ffd2f63e
    |   |-- plugins
    |   |   &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; kubernetes.io~empty-dir
    |   |       &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; wrapped_kube-api-access-7v75d
    |   |           &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; ready
    |   &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; volumes
    |       &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; kubernetes.io~projected
    |           &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; kube-api-access-7v75d
    |               |-- ca.crt -&amp;gt; ..data/ca.crt
    |               |-- namespace -&amp;gt; ..data/namespace
    |               &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; token -&amp;gt; ..data/token
    &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; d6d5a0a6-4c4a-4cc0-984f-a63129fbefca
        |-- plugins
        |   &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; kubernetes.io~empty-dir
        |       |-- wrapped_kube-api-access-c4l5m
        |       |   &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; ready
        |       &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; wrapped_kube-proxy
        |           &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; ready
        &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; volumes
            |-- kubernetes.io~configmap
            |   &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; kube-proxy
            |       |-- config.conf -&amp;gt; ..data/config.conf
            |       &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; kubeconfig.conf -&amp;gt; ..data/kubeconfig.conf
            &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; kubernetes.io~projected
                &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; kube-api-access-c4l5m
                    |-- ca.crt -&amp;gt; ..data/ca.crt
                    |-- namespace -&amp;gt; ..data/namespace
                    &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;--&lt;/span&gt; token -&amp;gt; ..data/token

25 directories, 24 files
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;q-why-theres-a-symmetric-token-used-by-kubeadm&quot;&gt;Q: why there’s a symmetric token used by kubeadm?&lt;/h3&gt;

&lt;p&gt;OK, I already feel I learnt quite a bit.&lt;/p&gt;

&lt;p&gt;Yet, our very first question is still not answered.&lt;br /&gt;
i.e., why there’s a symmetric token used by kubeadm?&lt;/p&gt;

&lt;p&gt;I was actually having a chat with the creator of Kubeadm himself, Lucas Käldström (yes, the same person who wrote the above linked thesis).&lt;/p&gt;

&lt;p&gt;What I learnt is - even though it’s a symmetric and shared string, the token itself has two parts, where the first part (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;token-id&lt;/code&gt;) is supposed to be treated as public entity and the second part (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;token-secret&lt;/code&gt;) to be treated as a private entity.&lt;/p&gt;

&lt;p&gt;Becuase, Kubeadm tokens are to be used for establishing bidirectional trust between the client (in our case, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;joining-node&lt;/code&gt;) and the server (the control-plane, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;api-server&lt;/code&gt;).&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;For the client (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;joining-node&lt;/code&gt;) to establish trust to the server (the control-plane, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;api-server&lt;/code&gt;), we saw the first part (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;token-id&lt;/code&gt;) of the token is used (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;system:bootstrap:pqrstu&lt;/code&gt; and the matching secret and clusterrolebinding).&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;For the server (the control-plane, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;api-server&lt;/code&gt;) to establish trust to the client (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;joining-node&lt;/code&gt;), the entire shared token (both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;token-id&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;token-secret&lt;/code&gt;) can be used.&lt;/p&gt;

    &lt;p&gt;If you look at the full &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubeadm join ...&lt;/code&gt; logs again, one of the early steps you will see is - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;attempting to download the KubeletConfiguration from ConfigMap &quot;kubelet-config&quot;&lt;/code&gt;.&lt;/p&gt;

    &lt;p&gt;This token (stored as the Secret object in the control-plane aka the server side) can be used to sign the ConfigMap (“kubelet-config”).&lt;/p&gt;

    &lt;p&gt;And then on the client side (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;joining-node&lt;/code&gt;), the received signed ConfigMap can then be authenticated by using the same shared token.&lt;/p&gt;

    &lt;p&gt;The process is explained here briefly - &lt;a href=&quot;https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/#configmap-signing&quot;&gt;ConfigMap Signing&lt;/a&gt;,&lt;br /&gt;
but the important part is - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;You can verify the JWS (signature) using the HS256 scheme (HMAC-SHA256) with the full token (e.g. 07401b.f395accd246ae52d) as the shared secret.&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, even though it’s a symmetric and a shared token, but it has similarities to the assymetric key pairs with its public and private entities used for separate purposes.&lt;/p&gt;

&lt;p&gt;There’s also this design proposal called, &lt;a href=&quot;https://github.com/kubernetes/design-proposals-archive/blob/main/cluster-lifecycle/bootstrap-discovery.md&quot;&gt;bootstrap discovery&lt;/a&gt;, which discusses and infact proposed the flow we see in our logs.&lt;/p&gt;

&lt;p&gt;Finally, I will end this post with this diagram which atleast for me, summarises nicely, the entire process we followed from start to end so far:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-pgsql&quot;&gt;New node
  │
  │ kubeadm join
  │
  ▼
API Server (unauthenticated)
  │
  │ token-based auth
  ▼
CSR created
  │
  │ CertificateSigningRequest
  ▼
Controller approves CSR
  │
  │ signed by CA
  ▼
kubelet gets client cert
  │
  │ mTLS from now on
  ▼
FULLY TRUSTED NODE
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With that, thank you for reading so far.&lt;/p&gt;

&lt;p&gt;And I hope you also got to learn a few new things. o/&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;PS:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Even though the node was able to join the control-plane, but it wasn’t really in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;READY&lt;/code&gt; state (and I left it there, didn’t troubleshoot it further).&lt;/p&gt;

&lt;p&gt;The Kubelet logs read something like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;failed to mount rootfs component: mount source &quot;overlay&quot; ... err: invalid argument
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description>
	<pubDate>Mon, 15 Dec 2025 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Sanyam Khurana: Fixing Doctest's &quot;line None&quot; Problem</title>
	<guid isPermaLink="false">tag:www.sanyamkhurana.com,2025-12-13:/blog/cpython-doctest-line-numbers.html</guid>
	<link>https://www.sanyamkhurana.com/blog/cpython-doctest-line-numbers.html</link>
	<description>&lt;p class=&quot;first last&quot;&gt;How I fixed a 10-year-old CPython bug that made doctest report &quot;line None&quot; for __test__ dictionary strings, making failures nearly impossible to locate.&lt;/p&gt;</description>
	<pubDate>Fri, 12 Dec 2025 18:30:00 +0000</pubDate>
</item>
<item>
	<title>Sanyam Khurana: Fixing a 17-Year-Old CPython Issue</title>
	<guid isPermaLink="false">tag:www.sanyamkhurana.com,2025-12-12:/blog/cpython-17-year-old-issue.html</guid>
	<link>https://www.sanyamkhurana.com/blog/cpython-17-year-old-issue.html</link>
	<description>&lt;p class=&quot;first last&quot;&gt;How I picked up a CPython issue from 2008, wrote a C extension patch, and got it merged into Python's stdlib 17 years later.&lt;/p&gt;</description>
	<pubDate>Thu, 11 Dec 2025 18:30:00 +0000</pubDate>
</item>
<item>
	<title>Priyanka Saggu: What happens when Kind doesn't have enough IP(s)?</title>
	<guid isPermaLink="true">https://psaggu.com/2025/12/06/kind-ip-constraint.html</guid>
	<link>https://psaggu.com/2025/12/06/kind-ip-constraint.html</link>
	<description>&lt;p&gt;I wanted to write a quick blog to document a tiny experiment I ran last week.&lt;br /&gt;
Just dumping my rough notes as it is.&lt;/p&gt;

&lt;p&gt;What I want to test is a scenario of creating a (Kind) cluster when it doesn’t have enough IP addresses, to assign internally etc.&lt;br /&gt;
Meaning I try to create a Kind cluster and give it only a docker bridge network with 20 or 50 IP addresses (basically a very tiny pool of IP(s)).&lt;/p&gt;

&lt;p&gt;Actually, now that I think more, 20-50 IP(s) are actually too much for my experiment.&lt;br /&gt;
Because the docker bridge IP pool will only be used for assigning IP(s) to the kind nodes (the control-plane and worker nodes).&lt;br /&gt;
Inside these kind nodes - for the Pods and for the Containers IP(s), the node will configure its own pool of private IP addresses, so that doesn’t come from the docker bridge network from the host.&lt;/p&gt;

&lt;p&gt;Therefore, the flow is roughly like:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;(my host network) sets aside a little set of private IP for the docker bridge -&amp;gt;&lt;/li&gt;
  &lt;li&gt;(then docker bridge network) assigns an IP to a node -&amp;gt;&lt;/li&gt;
  &lt;li&gt;(node internal network) which assigns IP(s) to pods and containers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this understanding now, I feel I should create a docker bridge network with even less IP(s), lets say 5 IP(s).&lt;br /&gt;
And with this newly created docker bridge network, if I try to create a Kind cluster with 5 or more nodes, atleast 1 node will never get an IP.&lt;br /&gt;
And that is exactly the behavior I want to test.&lt;/p&gt;

&lt;p&gt;I also know out of these 5 IP(s) -&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;one will be used as gateway, so that is gone,&lt;/li&gt;
  &lt;li&gt;and then the rest 4 will be assigned to 4 nodes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(Note: this above understanding is incomplete right now, will be fixed later in the post.)&lt;/p&gt;

&lt;p&gt;So, with that mathematics done now, let’s run the experiment.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;First off, create a Kind cluster:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ &lt;span class=&quot;nb&quot;&gt;cat &lt;/span&gt;kind-config.yaml 
&lt;span class=&quot;c&quot;&gt;# kind-config.yaml&lt;/span&gt;
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
  disableDefaultCNI: &lt;span class=&quot;nb&quot;&gt;true
&lt;/span&gt;nodes:
  - role: control-plane
  - role: worker
  - role: worker
  - role: worker
  - role: worker


❯ kind create cluster &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; ip-test &lt;span class=&quot;nt&quot;&gt;--retain&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--config&lt;/span&gt; kind-config.yaml
Creating cluster &lt;span class=&quot;s2&quot;&gt;&quot;ip-test&quot;&lt;/span&gt; ...
 ✓ Ensuring node image &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;kindest/node:v1.34.0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 🖼
 ✓ Preparing nodes 📦 📦 📦 📦 📦  
 ✓ Writing configuration 📜 
 ✓ Starting control-plane 🕹️ 
 ✓ Installing StorageClass 💾 
 ✓ Joining worker nodes 🚜 
Set kubectl context to &lt;span class=&quot;s2&quot;&gt;&quot;kind-ip-test&quot;&lt;/span&gt;
You can now use your cluster with:

kubectl cluster-info &lt;span class=&quot;nt&quot;&gt;--context&lt;/span&gt; kind-ip-test

Have a &lt;span class=&quot;nb&quot;&gt;nice &lt;/span&gt;day! 👋
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Number one&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To create a new docker bridge network, I need to run the following command:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ docker network create --driver bridge  \
    --subnet 172.20.0.0/29  \
    --gateway 172.20.0.1 \
    --aux-address &quot;reserved1=172.20.0.6&quot; \
    kind-small-net
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Notice the flag I passed, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--subnet 172.20.0.0/29&lt;/code&gt;.&lt;br /&gt;
This translates to a private IP network &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;172.20.0.0&lt;/code&gt; with a subnet mask of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;255.255.255.248/29&lt;/code&gt;.&lt;br /&gt;
This subnet mask will give me exactly 8 IP addresses.&lt;br /&gt;
(and that’s the closest I can get to making an IP pool with exact 5 usable IP(s)).&lt;/p&gt;

&lt;p&gt;So, how these 8 IP(s) will be used, is explained below:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;172.20.0.0&lt;/code&gt; = network (not usable)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;172.20.0.1&lt;/code&gt; → commonly used as gateway (Docker sets a gateway)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;172.20.0.2 – 172.20.0..6&lt;/code&gt; = usable host addresses (that’s 5 addresses here)&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;172.20.0.7&lt;/code&gt; = broadcast (not usable)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also notice, that I restricted one of the available 5 IP addresses using the flag, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--aux-address &quot;reserved1=172.20.0.6&quot;&lt;/code&gt; to create an IP contrained scenario.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Number two&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Kind always create a default docker network bridge with name “kind” automatically.&lt;/p&gt;

&lt;p&gt;So, I can try to create a new docker network bridge (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kind-small-net&lt;/code&gt;) with constrained IP pool like we did above.&lt;br /&gt;
And then try to connect existing Kind cluster nodes to this newly created bridge network.&lt;/p&gt;

&lt;p&gt;Like following:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;c &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;docker ps &lt;span class=&quot;nt&quot;&gt;--filter&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;name=ip-test&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-q&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do   &lt;/span&gt;docker network connect kind-small-net &lt;span class=&quot;nv&quot;&gt;$c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done
&lt;/span&gt;Error response from daemon: no available IPv4 addresses on this network&lt;span class=&quot;s1&quot;&gt;'s address pools: kind-small-net (15f712efffba69730048b9f826e3e68702646a37df4d09c86288fca47a5a52f6)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Notice, I got an error - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;no available IPv4 addresses on this network's address pools&lt;/code&gt;.&lt;br /&gt;
So far, everything is going as expected.&lt;/p&gt;

&lt;p&gt;Now, let’s check if anything happened to the cluster:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ kubectl get nodes -o wide
NAME                    STATUS     ROLES           AGE     VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE                         KERNEL-VERSION     CONTAINER-RUNTIME
ip-test-control-plane   NotReady   control-plane   9m4s    v1.34.0   172.18.0.6    &amp;lt;none&amp;gt;        Debian GNU/Linux 12 (bookworm)   6.17.9-1-default   containerd://2.1.3
ip-test-worker          NotReady   &amp;lt;none&amp;gt;          8m48s   v1.34.0   172.18.0.2    &amp;lt;none&amp;gt;        Debian GNU/Linux 12 (bookworm)   6.17.9-1-default   containerd://2.1.3
ip-test-worker2         NotReady   &amp;lt;none&amp;gt;          8m49s   v1.34.0   172.18.0.4    &amp;lt;none&amp;gt;        Debian GNU/Linux 12 (bookworm)   6.17.9-1-default   containerd://2.1.3
ip-test-worker3         NotReady   &amp;lt;none&amp;gt;          8m49s   v1.34.0   172.18.0.3    &amp;lt;none&amp;gt;        Debian GNU/Linux 12 (bookworm)   6.17.9-1-default   containerd://2.1.3
ip-test-worker4         NotReady   &amp;lt;none&amp;gt;          8m49s   v1.34.0   172.18.0.5    &amp;lt;none&amp;gt;        Debian GNU/Linux 12 (bookworm)   6.17.9-1-default   containerd://2.1.3


❯ docker container ps -a
CONTAINER ID   IMAGE                  COMMAND                  CREATED          STATUS          PORTS                       NAMES
aca02654b39a   kindest/node:v1.34.0   &quot;/usr/local/bin/entr…&quot;   13 minutes ago   Up 13 minutes                               ip-test-worker
a7da65a5a3f7   kindest/node:v1.34.0   &quot;/usr/local/bin/entr…&quot;   13 minutes ago   Up 13 minutes                               ip-test-worker4
4605b3acc669   kindest/node:v1.34.0   &quot;/usr/local/bin/entr…&quot;   13 minutes ago   Up 13 minutes                               ip-test-worker3
856fbf8aec0d   kindest/node:v1.34.0   &quot;/usr/local/bin/entr…&quot;   13 minutes ago   Up 13 minutes   127.0.0.1:46031-&amp;gt;6443/tcp   ip-test-control-plane
fcb796be89c8   kindest/node:v1.34.0   &quot;/usr/local/bin/entr…&quot;   13 minutes ago   Up 13 minutes                               ip-test-worker2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;NO! All nodes still has an IP assigned to them.&lt;br /&gt;
And none of these assigned IP(s) are from our newly created network bridge (atleast not in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kubectl&lt;/code&gt; output).  &lt;br /&gt;
(And yes, I also see the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotReady&lt;/code&gt; status, so that is something.)&lt;/p&gt;

&lt;p&gt;What’s going on? Let’s inspect both the network bridges:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ docker network inspect kind

        &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;kind&quot;&lt;/span&gt;,
         ...
        &lt;span class=&quot;s2&quot;&gt;&quot;Scope&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;local&quot;&lt;/span&gt;,
        &lt;span class=&quot;s2&quot;&gt;&quot;Driver&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;bridge&quot;&lt;/span&gt;,
         ...
        &lt;span class=&quot;s2&quot;&gt;&quot;IPAM&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            ...
            &lt;span class=&quot;s2&quot;&gt;&quot;Config&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;s2&quot;&gt;&quot;Subnet&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.18.0.0/16&quot;&lt;/span&gt;,
                    &lt;span class=&quot;s2&quot;&gt;&quot;Gateway&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.18.0.1&quot;&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
            &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
        ...
        &lt;span class=&quot;s2&quot;&gt;&quot;Containers&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;4605b3acc6699173bd975a3d6b74d25e688eecfce644962bd7fb26c50d42f890&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;ip-test-worker3&quot;&lt;/span&gt;,
                ...
                &lt;span class=&quot;s2&quot;&gt;&quot;IPv4Address&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.18.0.3/16&quot;&lt;/span&gt;,
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;856fbf8aec0d287fea50ce9255260a22a1f707e12ea34aac313e3b356ffc3d8d&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;ip-test-control-plane&quot;&lt;/span&gt;,
                ...
                &lt;span class=&quot;s2&quot;&gt;&quot;IPv4Address&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.18.0.6/16&quot;&lt;/span&gt;,
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;a7da65a5a3f7dc78947e33d8f797854c47630adbee68ea30a46590a5238862ac&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;ip-test-worker4&quot;&lt;/span&gt;,
                ...
                &lt;span class=&quot;s2&quot;&gt;&quot;IPv4Address&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.18.0.5/16&quot;&lt;/span&gt;,
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;aca02654b39a931e9d27e313f61a78719eb389cb008e86f078c184fac2bae4e7&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;ip-test-worker&quot;&lt;/span&gt;,
                ...
                &lt;span class=&quot;s2&quot;&gt;&quot;IPv4Address&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.18.0.2/16&quot;&lt;/span&gt;,
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;fcb796be89c800e6e6107026ab04f448b9efa889957c10253f181bd63fa88075&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;ip-test-worker2&quot;&lt;/span&gt;,
                ...
                &lt;span class=&quot;s2&quot;&gt;&quot;IPv4Address&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.18.0.4/16&quot;&lt;/span&gt;,
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ docker network inspect kind-small-net

        &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;kind-small-net&quot;&lt;/span&gt;,
         ...
        &lt;span class=&quot;s2&quot;&gt;&quot;Scope&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;local&quot;&lt;/span&gt;,
        &lt;span class=&quot;s2&quot;&gt;&quot;Driver&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;bridge&quot;&lt;/span&gt;,
         ...
        &lt;span class=&quot;s2&quot;&gt;&quot;IPAM&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            ...
            &lt;span class=&quot;s2&quot;&gt;&quot;Config&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;s2&quot;&gt;&quot;Subnet&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.20.0.0/29&quot;&lt;/span&gt;,
                    &lt;span class=&quot;s2&quot;&gt;&quot;Gateway&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.20.0.1&quot;&lt;/span&gt;,
                    &lt;span class=&quot;s2&quot;&gt;&quot;AuxiliaryAddresses&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;s2&quot;&gt;&quot;reserved1&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.20.0.6&quot;&lt;/span&gt;
                    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
        ...
        &lt;span class=&quot;s2&quot;&gt;&quot;Containers&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;4605b3acc6699173bd975a3d6b74d25e688eecfce644962bd7fb26c50d42f890&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;ip-test-worker3&quot;&lt;/span&gt;,
                ...
                &lt;span class=&quot;s2&quot;&gt;&quot;IPv4Address&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.20.0.4/29&quot;&lt;/span&gt;,
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;856fbf8aec0d287fea50ce9255260a22a1f707e12ea34aac313e3b356ffc3d8d&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;ip-test-control-plane&quot;&lt;/span&gt;,
                ...
                &lt;span class=&quot;s2&quot;&gt;&quot;IPv4Address&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.20.0.5/29&quot;&lt;/span&gt;,
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;a7da65a5a3f7dc78947e33d8f797854c47630adbee68ea30a46590a5238862ac&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;ip-test-worker4&quot;&lt;/span&gt;,
                ...
                &lt;span class=&quot;s2&quot;&gt;&quot;IPv4Address&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.20.0.3/29&quot;&lt;/span&gt;,
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;aca02654b39a931e9d27e313f61a78719eb389cb008e86f078c184fac2bae4e7&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;ip-test-worker&quot;&lt;/span&gt;,
                ...
                &lt;span class=&quot;s2&quot;&gt;&quot;IPv4Address&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.20.0.2/29&quot;&lt;/span&gt;,
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;OK, so, 4 out of the 5 nodes (1 control-plane + 3 workers) are assigned an IP from the new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kind-small-net&lt;/code&gt; network.&lt;/p&gt;

&lt;p&gt;But the entire set (1 control-plane + 4 workers) are still assigned an IP from the default &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kind&lt;/code&gt; network.&lt;/p&gt;

&lt;p&gt;Let’s try one more thing.&lt;br /&gt;
Just like the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker network connect&lt;/code&gt; command, there’s also a command to disconnect containers from a network as well.&lt;br /&gt;
Let’s run that as well and see if that makes the Kind cluster nodes fall back to the new &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;kind-small-net&lt;/code&gt; network IP(s).&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;c &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;docker ps &lt;span class=&quot;nt&quot;&gt;--filter&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;name=ip-test&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-q&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do   &lt;/span&gt;docker network disconnect kind &lt;span class=&quot;nv&quot;&gt;$c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;

❯ docker network inspect kind

        &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;kind&quot;&lt;/span&gt;,
        ...
        &lt;span class=&quot;s2&quot;&gt;&quot;Scope&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;local&quot;&lt;/span&gt;,
        &lt;span class=&quot;s2&quot;&gt;&quot;Driver&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;bridge&quot;&lt;/span&gt;,
        ...
        &lt;span class=&quot;s2&quot;&gt;&quot;IPAM&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            ...
            &lt;span class=&quot;s2&quot;&gt;&quot;Config&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;s2&quot;&gt;&quot;Subnet&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.18.0.0/16&quot;&lt;/span&gt;,
                    &lt;span class=&quot;s2&quot;&gt;&quot;Gateway&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.18.0.1&quot;&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
                ...
            &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
        ...
        &lt;span class=&quot;s2&quot;&gt;&quot;Containers&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{}&lt;/span&gt;,
        ...


❯ kubectl get nodes &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; wide
NAME                    STATUS     ROLES           AGE   VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE                         KERNEL-VERSION     CONTAINER-RUNTIME
ip-test-control-plane   NotReady   control-plane   28m   v1.34.0   172.18.0.6    &amp;lt;none&amp;gt;        Debian GNU/Linux 12 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;bookworm&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;   6.17.9-1-default   containerd://2.1.3
ip-test-worker          NotReady   &amp;lt;none&amp;gt;          28m   v1.34.0   172.18.0.2    &amp;lt;none&amp;gt;        Debian GNU/Linux 12 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;bookworm&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;   6.17.9-1-default   containerd://2.1.3
ip-test-worker2         NotReady   &amp;lt;none&amp;gt;          28m   v1.34.0   172.18.0.4    &amp;lt;none&amp;gt;        Debian GNU/Linux 12 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;bookworm&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;   6.17.9-1-default   containerd://2.1.3
ip-test-worker3         NotReady   &amp;lt;none&amp;gt;          28m   v1.34.0   172.18.0.3    &amp;lt;none&amp;gt;        Debian GNU/Linux 12 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;bookworm&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;   6.17.9-1-default   containerd://2.1.3
ip-test-worker4         NotReady   &amp;lt;none&amp;gt;          28m   v1.34.0   172.18.0.5    &amp;lt;none&amp;gt;        Debian GNU/Linux 12 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;bookworm&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;   6.17.9-1-default   containerd://2.1.3

❯ &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;c &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;docker ps &lt;span class=&quot;nt&quot;&gt;--filter&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;name=ip-test&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-q&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do   &lt;/span&gt;docker network disconnect kind &lt;span class=&quot;nv&quot;&gt;$c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done
&lt;/span&gt;Error response from daemon: container aca02654b39a931e9d27e313f61a78719eb389cb008e86f078c184fac2bae4e7 is not connected to network kind
Error response from daemon: container a7da65a5a3f7dc78947e33d8f797854c47630adbee68ea30a46590a5238862ac is not connected to network kind
Error response from daemon: container 4605b3acc6699173bd975a3d6b74d25e688eecfce644962bd7fb26c50d42f890 is not connected to network kind
Error response from daemon: container 856fbf8aec0d287fea50ce9255260a22a1f707e12ea34aac313e3b356ffc3d8d is not connected to network kind
Error response from daemon: container fcb796be89c800e6e6107026ab04f448b9efa889957c10253f181bd63fa88075 is not connected to network kind
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ok! So, all Kind nodes are indeed disconnected from the default “Kind” network now.&lt;br /&gt;
But still, they have an IP assigned from the old “Kind” network only (i.e, it didn’t fall back to the newly created bridge “kind-small-net”).&lt;/p&gt;

&lt;p&gt;So, looks like Kind only look for the default automatically created docker bridge network (“Kind”) for its cluster configuration.&lt;/p&gt;

&lt;p&gt;And therefore, regardless of me creating a new docker network bridge and attaching existing Kind node containers to that, Kind will always assign IP(s) from this default network bridge to the kind nodes.&lt;br /&gt;
And so, no IP exhaustion scenaio will happen.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Number three&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If I still want the Kind cluster to use a custom IP pool, the way to do that is:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;delete the existing docker network bridge, with name “Kind” (if one is existing), and&lt;/li&gt;
  &lt;li&gt;recreate a new one manually, with the same name “Kind”, with the required custom tiny IP pool I need.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Like following:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ docker network rm kind
kind

❯ docker network inspect kind
[]
Error response from daemon: network kind not found


❯ docker network create --driver bridge  \
    --subnet 172.20.0.0/29  \
    --gateway 172.20.0.1 \
    --aux-address &quot;reserved1=172.20.0.6&quot; \
    kind

f64a9d47cf585e9e61c3d25da2b3d3684f02b633b53ee7c053a60c2da0eafd84

❯ docker network inspect kind

        &quot;Name&quot;: &quot;kind&quot;,
        &quot;Id&quot;: &quot;f64a9d47cf585e9e61c3d25da2b3d3684f02b633b53ee7c053a60c2da0eafd84&quot;,
        &quot;Created&quot;: &quot;2025-12-16T18:35:37.818562813+05:30&quot;,
        &quot;Scope&quot;: &quot;local&quot;,
        &quot;Driver&quot;: &quot;bridge&quot;,
        ...
        &quot;IPAM&quot;: {
            ...
            &quot;Config&quot;: [
                {
                    &quot;Subnet&quot;: &quot;172.20.0.0/29&quot;,
                    &quot;Gateway&quot;: &quot;172.20.0.1&quot;,
                    &quot;AuxiliaryAddresses&quot;: {
                        &quot;reserved1&quot;: &quot;172.20.0.6&quot;
                    }
                }
            ]
        },
        ...
        &quot;ConfigOnly&quot;: false,
        &quot;Containers&quot;: {},
        ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And with the required IP constrained docker bridge network with name “kind” in place, let’s create the Kind cluster as following:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ kind create cluster --name ip-test --retain --config kind-config.yaml
Creating cluster &quot;ip-test&quot; ...
 ✓ Ensuring node image (kindest/node:v1.34.0) 🖼
 ✗ Preparing nodes 📦 📦 📦 📦 📦  
ERROR: failed to create cluster: command &quot;docker run --name ip-test-worker2 --hostname ip-test-worker2 --label io.x-k8s.kind.role=worker --privileged --security-opt seccomp=unconfined --security-opt apparmor=unconfined --tmpfs /tmp --tmpfs /run --volume /var --volume /lib/modules:/lib/modules:ro -e KIND_EXPERIMENTAL_CONTAINERD_SNAPSHOTTER --detach --tty --label io.x-k8s.kind.cluster=ip-test --net kind --restart=on-failure:1 --init=false --cgroupns=private --volume /dev/mapper:/dev/mapper kindest/node:v1.34.0@sha256:7416a61b42b1662ca6ca89f02028ac133a309a2a30ba309614e8ec94d976dc5a&quot; failed with error: exit status 125
Command Output: a14eea4647334a84e95142893a735d1cf97bcb74def2793de4a6653c6f187cc9
docker: Error response from daemon: failed to set up container networking: no available IPv4 addresses on this network's address pools: kind (f64a9d47cf585e9e61c3d25da2b3d3684f02b633b53ee7c053a60c2da0eafd84)

Run 'docker run --help' for more information
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;OK, we managed to get the scenario working.&lt;br /&gt;
This time, the cluster failed at the bootstrap time only, with the expected error:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;failed to &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;up container networking: no available IPv4 addresses on this network&lt;span class=&quot;s1&quot;&gt;'s address pools: kind
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And once again, docker network inspect also shows that node &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ip-test-worker2&lt;/code&gt; was the one which failed to get an IP from the pool.&lt;br /&gt;
Plus, the cluster is not responding.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ docker network inspect kind

        &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;kind&quot;&lt;/span&gt;,
        &lt;span class=&quot;s2&quot;&gt;&quot;Id&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;f64a9d47cf585e9e61c3d25da2b3d3684f02b633b53ee7c053a60c2da0eafd84&quot;&lt;/span&gt;,
        &lt;span class=&quot;s2&quot;&gt;&quot;Created&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;2025-12-16T18:35:37.818562813+05:30&quot;&lt;/span&gt;,
        &lt;span class=&quot;s2&quot;&gt;&quot;Scope&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;local&quot;&lt;/span&gt;,
        &lt;span class=&quot;s2&quot;&gt;&quot;Driver&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;bridge&quot;&lt;/span&gt;,
        ...
        &lt;span class=&quot;s2&quot;&gt;&quot;IPAM&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            ...
            &lt;span class=&quot;s2&quot;&gt;&quot;Config&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;s2&quot;&gt;&quot;Subnet&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.20.0.0/29&quot;&lt;/span&gt;,
                    &lt;span class=&quot;s2&quot;&gt;&quot;Gateway&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.20.0.1&quot;&lt;/span&gt;,
                    &lt;span class=&quot;s2&quot;&gt;&quot;AuxiliaryAddresses&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;s2&quot;&gt;&quot;reserved1&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.20.0.6&quot;&lt;/span&gt;
                    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
        ...
        &lt;span class=&quot;s2&quot;&gt;&quot;Containers&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;s2&quot;&gt;&quot;2230663632be9887858ac1037b1f01ec856122bf5ab02e6acf9188c6bfb12b32&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;ip-test-worker3&quot;&lt;/span&gt;,
                ...
                &lt;span class=&quot;s2&quot;&gt;&quot;IPv4Address&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.20.0.3/29&quot;&lt;/span&gt;,
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;6be8bb30074055a2049ccb50d066f0b1cd9cf62243f3d3c619b16c0e555dcf80&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;ip-test-control-plane&quot;&lt;/span&gt;,
                ...
                &lt;span class=&quot;s2&quot;&gt;&quot;IPv4Address&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.20.0.4/29&quot;&lt;/span&gt;,
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;7c545d00e21bbea07ed9a22226c80753acf09d3ed574914e711a8ddc67847013&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;ip-test-worker4&quot;&lt;/span&gt;,
                ...
                &lt;span class=&quot;s2&quot;&gt;&quot;IPv4Address&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.20.0.2/29&quot;&lt;/span&gt;,
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
            &lt;span class=&quot;s2&quot;&gt;&quot;f7b35fb4319944ba1ef7fb426e1708bac1bad0601b29d6cd1f43a2a4acb41233&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;s2&quot;&gt;&quot;Name&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;ip-test-worker&quot;&lt;/span&gt;,
                ...
                &lt;span class=&quot;s2&quot;&gt;&quot;IPv4Address&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;172.20.0.5/29&quot;&lt;/span&gt;,
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

❯ kubectl get nodes
E1216 18:40:11.021156  144524 memcache.go:265] &lt;span class=&quot;s2&quot;&gt;&quot;Unhandled Error&quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;couldn't get current server API group list: Get &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;http://localhost:8080/api?timeout=32s&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;: dial tcp [::1]:8080: connect: connection refused&quot;&lt;/span&gt;
The connection to the server localhost:8080 was refused - did you specify the right host or port?

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Number four&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When I ran the “kind create cluster” command above, I learnt there’s a flag called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--retain&lt;/code&gt; that will retain the nodes (the respective docker containers) even if cluster bootstrap fails, for debugging purposes.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ docker container ps &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt;
CONTAINER ID   IMAGE                  COMMAND                  CREATED         STATUS         PORTS                       NAMES
a14eea464733   kindest/node:v1.34.0   &lt;span class=&quot;s2&quot;&gt;&quot;/usr/local/bin/entr…&quot;&lt;/span&gt;   6 minutes ago   Created                                    ip-test-worker2
2230663632be   kindest/node:v1.34.0   &lt;span class=&quot;s2&quot;&gt;&quot;/usr/local/bin/entr…&quot;&lt;/span&gt;   6 minutes ago   Up 6 minutes                               ip-test-worker3
6be8bb300740   kindest/node:v1.34.0   &lt;span class=&quot;s2&quot;&gt;&quot;/usr/local/bin/entr…&quot;&lt;/span&gt;   6 minutes ago   Up 6 minutes   127.0.0.1:38589-&amp;gt;6443/tcp   ip-test-control-plane
7c545d00e21b   kindest/node:v1.34.0   &lt;span class=&quot;s2&quot;&gt;&quot;/usr/local/bin/entr…&quot;&lt;/span&gt;   6 minutes ago   Up 6 minutes                               ip-test-worker4
f7b35fb43199   kindest/node:v1.34.0   &lt;span class=&quot;s2&quot;&gt;&quot;/usr/local/bin/entr…&quot;&lt;/span&gt;   6 minutes ago   Up 6 minutes                               ip-test-worker

❯ docker &lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-it&lt;/span&gt; ip-test-control-plane /bin/bash
root@ip-test-control-plane:/# &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;

❯ &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;c &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;docker ps &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--filter&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;name=ip-test&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-q&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do   &lt;/span&gt;docker inspect &lt;span class=&quot;nt&quot;&gt;--format&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;' '&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$c&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
/ip-test-worker2 
/ip-test-worker3 172.20.0.3
/ip-test-control-plane 172.20.0.4
/ip-test-worker4 172.20.0.2
/ip-test-worker 172.20.0.5
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can see that all containers have an IP assigned to them from our new custom “kind” network bridge, but not the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ip-test-worker2&lt;/code&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Number five&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ok, let’s finish it with fixing our cluster.&lt;/p&gt;

&lt;p&gt;Let’s recreate the “kind” network bridge.&lt;br /&gt;
It is going to be a custom network even now, but let’s remove the restriction for that last available and usable IP address.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;❯ docker network create &lt;span class=&quot;nt&quot;&gt;--driver&lt;/span&gt; bridge      &lt;span class=&quot;nt&quot;&gt;--subnet&lt;/span&gt; 172.20.0.0/29      &lt;span class=&quot;nt&quot;&gt;--gateway&lt;/span&gt; 172.20.0.1    kind
0272f4e1a9d33eaf31a77a5aec2dece1cf95098345fb1b0bbbcb825901af0c2b

❯ kind create cluster &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; ip-test &lt;span class=&quot;nt&quot;&gt;--retain&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--config&lt;/span&gt; kind-config.yaml
Creating cluster &lt;span class=&quot;s2&quot;&gt;&quot;ip-test&quot;&lt;/span&gt; ...
 ✓ Ensuring node image &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;kindest/node:v1.34.0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 🖼
 ✓ Preparing nodes 📦 📦 📦 📦 📦  
 ✓ Writing configuration 📜 
 ✓ Starting control-plane 🕹️ 
 ✓ Installing StorageClass 💾 
 ✓ Joining worker nodes 🚜 
Set kubectl context to &lt;span class=&quot;s2&quot;&gt;&quot;kind-ip-test&quot;&lt;/span&gt;
You can now use your cluster with:

kubectl cluster-info &lt;span class=&quot;nt&quot;&gt;--context&lt;/span&gt; kind-ip-test

Have a &lt;span class=&quot;nb&quot;&gt;nice &lt;/span&gt;day! 👋

❯ kubectl get nodes &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; wide
NAME                    STATUS     ROLES           AGE   VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE                         KERNEL-VERSION     CONTAINER-RUNTIME
ip-test-control-plane   NotReady   control-plane   41s   v1.34.0   172.20.0.6    &amp;lt;none&amp;gt;        Debian GNU/Linux 12 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;bookworm&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;   6.17.9-1-default   containerd://2.1.3
ip-test-worker          NotReady   &amp;lt;none&amp;gt;          26s   v1.34.0   172.20.0.5    &amp;lt;none&amp;gt;        Debian GNU/Linux 12 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;bookworm&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;   6.17.9-1-default   containerd://2.1.3
ip-test-worker2         NotReady   &amp;lt;none&amp;gt;          26s   v1.34.0   172.20.0.3    &amp;lt;none&amp;gt;        Debian GNU/Linux 12 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;bookworm&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;   6.17.9-1-default   containerd://2.1.3
ip-test-worker3         NotReady   &amp;lt;none&amp;gt;          26s   v1.34.0   172.20.0.2    &amp;lt;none&amp;gt;        Debian GNU/Linux 12 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;bookworm&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;   6.17.9-1-default   containerd://2.1.3
ip-test-worker4         NotReady   &amp;lt;none&amp;gt;          26s   v1.34.0   172.20.0.4    &amp;lt;none&amp;gt;        Debian GNU/Linux 12 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;bookworm&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;   6.17.9-1-default   containerd://2.1.3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Done! We have the nodes created with IP addresses assigned from the new custom “kind” network pool.&lt;/p&gt;

&lt;p&gt;I know the state of the nodes are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotReady&lt;/code&gt;, but that’s not part of this experiment.&lt;br /&gt;
(updated later - I know the reason why all nodes stayed in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotReady&lt;/code&gt; state. Because I only used a kind-config that disabled default CNI setup 🤦‍♀️. Anyway, removing this should fix it.)&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;networking&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;disableDefaultCNI&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, I want to try is to see what happens when I constrain “PodCIDR” and “ServiceCIDR” pools. o/&lt;/p&gt;</description>
	<pubDate>Sat, 06 Dec 2025 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Sandeep Choudhary: Git Worktree</title>
	<guid isPermaLink="true">https://blogs.dgplug.org/sandeepk/git-worktree</guid>
	<link>https://blogs.dgplug.org/sandeepk/git-worktree</link>
	<description>&lt;p&gt;A few days ago, during our office knowledge-sharing meeting, someone introduced the &lt;code&gt;git worktree&lt;/code&gt; command. It lets you create a new branch &lt;em&gt;parallel&lt;/em&gt; to your current working branch so you can start something new — or handle a hotfix — &lt;strong&gt;without stashing or committing your unfinished changes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It turned out to be incredibly useful. With &lt;code&gt;git worktree&lt;/code&gt;, you can maintain multiple working directories linked to the same Git repository with almost no friction.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;why-use-worktrees&quot;&gt;Why use worktrees?&lt;/h2&gt;

&lt;p&gt;Imagine you're working on a long-running feature — say, an optimization — and suddenly you’re assigned an urgent production bug.
Typically, you would stash your changes or make a temporary commit, switch branches, fix the bug, then restore everything. It's annoying and error-prone.&lt;/p&gt;

&lt;p&gt;With worktrees, you can directly spin up a parallel working directory:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git worktree add &amp;lt;path&amp;gt;
# Example:
git worktree add ../hotfix
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This creates a &lt;strong&gt;new linked worktree&lt;/strong&gt;, associated with your current repository, with its own metadata and branch checkout. Your original work remains untouched.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;removing-a-worktree&quot;&gt;Removing a worktree&lt;/h2&gt;

&lt;p&gt;Once you're done with the hotfix (or any task), removing the worktree is just as simple:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git worktree remove &amp;lt;path&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you delete the directory manually, Git will eventually clean up its administrative files automatically (based on &lt;code&gt;gc.worktreePruneExpire&lt;/code&gt; in &lt;code&gt;git-config&lt;/code&gt;).
You can also remove stale entries explicitly:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git worktree prune
&lt;/code&gt;&lt;/pre&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;other-useful-worktree-commands&quot;&gt;Other useful worktree commands&lt;/h2&gt;

&lt;h3 id=&quot;1-create-a-throwaway-worktree-detached-head&quot;&gt;1. Create a throwaway worktree (detached HEAD)&lt;/h3&gt;

&lt;p&gt;Perfect for quick experiments:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git worktree add -d &amp;lt;path&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;2-create-a-worktree-for-an-existing-branch&quot;&gt;2. Create a worktree for an existing branch&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git worktree add &amp;lt;path&amp;gt; &amp;lt;branch&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This checks out the given branch into a new, isolated working directory.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;further-reading&quot;&gt;Further reading&lt;/h2&gt;

&lt;p&gt;To dive deeper into &lt;code&gt;git worktree&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Official docs: &lt;a href=&quot;https://git-scm.com/docs/git-worktree&quot; rel=&quot;nofollow&quot;&gt;https://git-scm.com/docs/git-worktree&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Or simply run:&lt;/li&gt;&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;  git help worktree
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;hashtag&quot; href=&quot;https://blogs.dgplug.org/sandeepk/tag:Git&quot; rel=&quot;nofollow&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;span class=&quot;p-category&quot;&gt;Git&lt;/span&gt;&lt;/a&gt; &lt;a class=&quot;hashtag&quot; href=&quot;https://blogs.dgplug.org/sandeepk/tag:TIL&quot; rel=&quot;nofollow&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;span class=&quot;p-category&quot;&gt;TIL&lt;/span&gt;&lt;/a&gt; &lt;a class=&quot;hashtag&quot; href=&quot;https://blogs.dgplug.org/sandeepk/tag:Worktree&quot; rel=&quot;nofollow&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;span class=&quot;p-category&quot;&gt;Worktree&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Sun, 30 Nov 2025 13:27:11 +0000</pubDate>
</item>
<item>
	<title>Titas Dey: How to do polymorphism in C ?</title>
	<guid isPermaLink="true">https://blogs.dgplug.org/titas/how-to-do-polymorphism-in-c</guid>
	<link>https://blogs.dgplug.org/titas/how-to-do-polymorphism-in-c</link>
	<description>&lt;p&gt;Well the title is a clickbait,but it’s true in a limited sense.&lt;/p&gt;

&lt;p&gt;If you've written some C code you've probably used most of the features in C like &lt;code&gt;structure&lt;/code&gt;,&lt;code&gt;functions&lt;/code&gt;,&lt;code&gt;pointers&lt;/code&gt;,&lt;code&gt;arrays&lt;/code&gt; and perhaps even the &lt;code&gt;preprocessor&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, I will talk about one of the lesser used features in C  – &lt;strong&gt;union&lt;/strong&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;the-union&quot;&gt;The Union&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;union&lt;/code&gt; allocates a single shared block of memory, large enough to hold its &lt;strong&gt;largest member&lt;/strong&gt; (with some padding, depending on alignment).
Unlike a &lt;code&gt;struct&lt;/code&gt;, which allocates distinct memory for each member, a &lt;code&gt;union&lt;/code&gt; allows multiple members to occupy the same memory space.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#include&amp;lt;stdio.h&amp;gt;
#include&amp;lt;string.h&amp;gt;

struct xyz {
    int x;
    float y;
    char z[10];
};

union tuv {
    int t;
    float u;
    char v[10];
};

int main(void) {
    struct xyz st_eg;
    union tuv un_eg;

    printf(&quot;%d\n&quot;, sizeof(st_eg)); // O/P: 20 bytes (4 + 4 + 10 + 2 bytes padding)
    printf(&quot;%d\n&quot;, sizeof(un_eg)); // O/P: 12 bytes (10 bytes for v + 2 bytes padding)

    strcpy(&amp;amp;un_eg.v, &quot;HelloWorld&quot;);

    printf(&quot;%s\n&quot;, un_eg.v);  // O/P: HelloWorld 
    printf(&quot;%f\n&quot;, un_eg.u);  // O/P: 1143139122437582505939828736.000000

    return 0;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here, both the integer, float, and character array occupy the &lt;strong&gt;same memory region&lt;/strong&gt;.
When &lt;code&gt;&quot;HelloWorld&quot;&lt;/code&gt; is copied into the character array &lt;code&gt;v&lt;/code&gt;, reading that memory as a float outputs the string &lt;code&gt;&quot;HelloWorld&quot;&lt;/code&gt; typecasted into float
a short essay on &lt;strong&gt;union&lt;/strong&gt;.&lt;/p&gt;

&lt;hr /&gt;
&lt;ul&gt;&lt;li&gt;&lt;strong&gt;But why do we need union ?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Why to allocate memory for only the largest member and not all of them using struct ?&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;A union is valuable when you want &lt;strong&gt;different interpretations of the same memory&lt;/strong&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;example-1-storing-an-ipv4-address&quot;&gt;Example 1: Storing an IPv4 Address&lt;/h2&gt;

&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#include&amp;lt;stdio.h&amp;gt;

typedef union {
    unsigned int ip_add;
    unsigned char bytes[4];
} ipv4_add;

int main(void) {
    ipv4_add my_address = {0};

    my_address.bytes[0] = 127;
    my_address.bytes[1] = 55;
    my_address.bytes[2] = 115;
    my_address.bytes[3] = 0;

    printf(&quot;%x\n&quot;, my_address.ip_add); // O/P: 73377f
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;explanation&quot;&gt;Explanation&lt;/h3&gt;

&lt;p&gt;Using a union, we can store both the &lt;strong&gt;integer representation&lt;/strong&gt; and the &lt;strong&gt;byte-wise representation&lt;/strong&gt; of an IPv4 address within the same space.
This approach eliminates the need for explicit bit-shifting or manual conversions.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;example-2-unions-in-embedded-programming&quot;&gt;Example 2: Unions in Embedded Programming&lt;/h2&gt;

&lt;p&gt;Unions are widely used in embedded systems to represent &lt;strong&gt;hardware registers&lt;/strong&gt; that can be accessed both as a whole and as individual fields.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#include&amp;lt;stdio.h&amp;gt;

union HWRegister {
    struct { // annonymous structure
        unsigned char parity;
        unsigned char control;
        unsigned char stopbits;
        unsigned char direction;
    };
    unsigned int reg;
};

int main(void) {
    union HWRegister gpioa;

    gpioa.reg = 0x14424423;
    printf(&quot;%x\n&quot;, gpioa.stopbits); // O/P: 14

    return 0;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this example, the same memory can be accessed as a single 32-bit register or through specific bit fields.
This design improves clarity while maintaining memory efficiency — a common requirement in low-level programming.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;example-3-a-glimpse-of-polymorphism-in-c&quot;&gt;Example 3: A Glimpse of Polymorphism in C&lt;/h2&gt;

&lt;p&gt;Now coming back to the title , we can do something similar to OOP in C:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#include&amp;lt;stdio.h&amp;gt;

typedef enum {
    JSON_STR,
    JSON_BYTE,
    JSON_INT,
} json_type_t;

#define JSON_MAX_STR 64

typedef struct {
   json_type_t type;
   union {
       char str[JSON_MAX_STR];
       char byte;
       int number;
   };
} json_t;

void printJSON(json_t *json) {
    switch (json-&amp;gt;type) {
        case JSON_STR:
            printf(&quot;%s\n&quot;, json-&amp;gt;str);
            break;
        case JSON_BYTE:
            printf(&quot;%c\n&quot;, json-&amp;gt;byte);
            break;
        case JSON_INT:
            printf(&quot;%d\n&quot;, json-&amp;gt;number);
            break;
    }
}

int main(void) {
    json_t myJSON;
    myJSON.type = JSON_INT;
    myJSON.number = 97;

    printJSON(&amp;amp;myJSON);
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here, the structure &lt;code&gt;json_t&lt;/code&gt; can hold one of several possible data types — a string, a single byte, or an integer.
The active type is determined at runtime using the &lt;code&gt;type&lt;/code&gt; field.&lt;/p&gt;

&lt;p&gt;There are some issues in this , in C the types are not &lt;em&gt;tightly enforced by the compiler&lt;/em&gt; , so if we do&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;myJSON.type = JSON_STR;// // instead of JSON_INT
myJSON.number = 97;
printJSON(&amp;amp;myJSON); // O/P: a 
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;&lt;li&gt;The output will be : a (the ascii charector of value 97)&lt;/li&gt;&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;And that's all.&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;print(&quot;Titas , signing out &quot;)
&lt;/code&gt;&lt;/pre&gt;</description>
	<pubDate>Thu, 06 Nov 2025 14:31:29 +0000</pubDate>
</item>
<item>
	<title>Priyanka Saggu: Rescue OpenSUSE Tumbleweed (recreate Grub config from Rescue System)</title>
	<guid isPermaLink="true">https://psaggu.com/2025/11/02/opensuse-tw-grub-fix.html</guid>
	<link>https://psaggu.com/2025/11/02/opensuse-tw-grub-fix.html</link>
	<description>&lt;p&gt;In last 6 months time, twice I had to get my work machine’s system board (the motherboard) replaced.&lt;/p&gt;

&lt;p&gt;First for an “Integrated Graphics Error”. One day I got these very annoying beeps on my work machine, I ran a Lenovo Smartbeep scan using their mobile app, and it suggested to contact (immediately) Lenovo support and request for a system board replacement.&lt;/p&gt;

&lt;p&gt;Second time, the Wi-Fi (infact all wireless) stopped working on my machine.&lt;/p&gt;

&lt;p&gt;For a few weeks following the first system board replacement, I thought it was some wifi firmware mismatch issue on my OpenSUSE Tumbleweed (TW) machine.&lt;br /&gt;
Because TW is a rolling release, once in a while distribution upgrade breaks stuff, so its a normal thing.&lt;br /&gt;
But I remember for the first few weeks after the hardware replacement, the Wi-Fi worked sometimes.&lt;br /&gt;
The Network manager will detect it but then soon after, it started to drop entirely. And I would get “Wifi adapter not found”.&lt;br /&gt;
And then from last ~1.5 months, I have been relying entirely on an Ethernet for Internet on my work machine.&lt;br /&gt;
And that won’t work when I’m travelling (I know, I can get an external dongle or something, but still).&lt;/p&gt;

&lt;p&gt;So, I tried booting with a live USB stick into a Mint Cinnamon machine, and it was clear, it’s not a TW issue. Mint also didn’t detect any wireless network - zero, nil, nothing.&lt;br /&gt;
(Not to say, over last months, when I thought it was a firmware issue, I had tried many things, lots around the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;iwlwifi&lt;/code&gt; firmware, but nothing worked. I have been eying many recent upstream kernel bugzillas related to iwlwifi and I was convinced it was a firmwae issue. And it wasn’t).&lt;/p&gt;

&lt;p&gt;Now, very fortunately, Lenovo Premium Support just works.&lt;br /&gt;
(for me it did! Twice I contacted them in last 6 months, and both times an engineer visited almost on the next day or in two, basically as soon as they had the replacement component delivered to them.)&lt;br /&gt;
Both times, they replaced the mother board.&lt;br /&gt;
(My work machine is a ThinkPad Workstation and every thing is just stuck on the mother board, so any tiny chip dies and it requires a full system board replacement).&lt;/p&gt;

&lt;p&gt;Both times when the mother board was replaced, it’s almost a new machine, only with the same old storage.&lt;br /&gt;
(Very very important storage. Because it still contains my old TW OS partitions and data, and all the precious system configurations which takes a very long time to configure again).&lt;br /&gt;
I did run backups before both replacements, but still it’s a pain if I have to do a fresh OS reinstallation and setup everything again, in the middle of a work week.&lt;/p&gt;

&lt;p&gt;So, when the system board is replaced, I think it refreshes the BIOS, and my grub menu no longer sees the TW OS partitions and so it just directly boots into the mighty Windows Blue Screen screaming “the system can’t be fixed, and I need to do a fresh install”.&lt;/p&gt;

&lt;p&gt;But don’t get fooled by that (not immediately, check once).&lt;br /&gt;
Chances are that the old OS partitions are still there, just not being detected by the Grub Bootloader.&lt;br /&gt;
And that was the case for me (both times).&lt;/p&gt;

&lt;p&gt;And not to my surprise, the OpenSUSE TW “Rescue System” menu came to my resuce!&lt;br /&gt;
(well, to my surprise! Because let’s not forget, TW is a rolling release OS. So things &lt;em&gt;can&lt;/em&gt; go south very very quickly.)&lt;/p&gt;

&lt;p&gt;I did the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;I created a live USB stick with OpenSUSE Tumbleweed.&lt;br /&gt;
(It helped to have a stick with a full Offline image, and not the tiny Network image which will pull every single thing from Internet.&lt;br /&gt;
Because remember “the Wi-FI not working on my machine”.&lt;br /&gt;
Well I could have connected to Ethernet but still, the lesson is to have a proper stick ready with an offline image so it should just boot.)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Now, put it in the machine, go to the “Boot Menu” (F10, IIRC), and pick the option to boot from the live USB stick.&lt;br /&gt;
It will go to a grub menu.&lt;br /&gt;
Skip all the immediate menu options like “OpenSUSE Tumbleweed installation”, etc.&lt;br /&gt;
Go to “More …” and then “Rescue System”.&lt;br /&gt;
It will do the usual “loading basic drivers &amp;gt; hardware detection &amp;gt; ask to pick a keyboard layout, et. al” and then give me the “Resuce Login:” prompt.&lt;br /&gt;
Remember the username is “root” and there is no password.&lt;br /&gt;
With that, I enter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tty1:resuce:/ #&lt;/code&gt;.&lt;/p&gt;

    &lt;p&gt;Now run the following set of commands:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# first things first, check my disk and partitions
## (if they still exists, I move on. Otherwise, all is gone and nothing more to do)

fdisk -l
## gives me something like following (truncated ofcourse, to the important bits)
Disk /dev/nvme0n1: xx.xx GiB, xxxxxx bytes, xxxxxx sectors
Disk model: xxx PC xxxx xxxxx-xxxx-xxxx          
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: xxx
Disk identifier: xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxx

Device           Start   End     Sectors   Size       Type
/dev/nvme0n1p1   xxx     xxxx    xxxxx     260M       EFI System
/dev/nvme0n1p2   xxxx    xxxxx   xxxx      xxx.xxG    Linux filesystem
/dev/nvme0n1p3   xxxxx   xxxxx   xxxx      2G Linux   swap

# in my case, the disk that has the OpenSUSE tumbleweed is &quot;/dev/nvme0n1&quot;.
# &quot;/dev/nvme0n1p1&quot; is the EFI partition
# &quot;/dev/nvme0n1p2&quot; is the root partition
# &quot;/dev/nvme0n1p3&quot; is the Swap partition
  
# From this step onwards:
# I need &quot;/dev/nvme0n1p1&quot; (EFI System) and &quot;/dev/nvme0n1p2&quot; (Linux Filesystem)
  
# I need to mount these two partitions under &quot;/mnt&quot;
# (make sure the `/mnt` directory is empty before mounting anything to it)

cd /mnt
ls  # should be empty
cd ..

mount /dev/nvme0n1p2 /mnt
mount /dev/nvme0n1p1 /mnt/boot/efi
  
# next I need to mount &quot;/dev&quot;, &quot;/proc&quot;, &quot;/sys&quot;, &quot;/run&quot; from the live environment into the mount directory

mount -B /dev /mnt/dev
mount -B /proc /mnt/proc
mount -B /sys /mnt/sys
mount -B /run /mnt/run

# now chroot into the &quot;/mnt&quot; directory
# the prompt will turn into `resuce:/ #` from the earlier `tty1:resuce:/ #`

chroot /mnt   

# now make the EFI variables available

mount -t efivarfs none /sys/firmware/efi/efivars

# now reinstall grub2, with `grub2-install`

grub2-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=opensuse
## should output something like:
Installing for x86_64-efi platform.
Installation finished. No error reported.

# then probe for other operating systems on this machine
  
os-prober
## should output something like (and because my machine originally came with Windows, it still shows remnants of that)
/dev/nvme0n1p1@/EFI/Microsoft/Boot/bootmgfw.efi:Windows Boot Manager:Windows:efi

# now, create a new grub configuration file using grub2-mkconfig

grub2-mkconfig -o /boot/grub2/grub.cfg
## should output something like:
Generating grub configuraiton file ...
Found theme: /boot/grub2/themes/opneSUSE/theme.txt
Found linux image: /boot/vmlinuz-x.xx.x-x-default
Found initrd image: /boot/initrd-x.xx.x-x-default
Warning: os-prober will be executed to detect other bootable partitions.
Its output will be used to detect bootable binaries on them and create new boot entries.
Found Windows Boot manager on /dev/nvme0n1p1@/EFI/Microsoft/Boot/bootmgfw.efi
Adding boot menu entry for UEFI Firmware Settings ...
done

# If all good so far, exit out of chroot

exit

# Reboot the machine.
# And remove the installation media

reboot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;As the system reboots (remember I have removed the installation media at this point), I go to the BIOS to confirm the boot order.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Now, I let it boot normally and it should give me a grub menu with proper “OpenSUSE Tumbleweed” boot entry.&lt;br /&gt;
And that should work like before.&lt;br /&gt;
Boot and login! (It did, twice I followed this process and it did).&lt;/p&gt;

    &lt;p&gt;(A note - When I reboot into OpenSUSE TW after this new grub config creation on a new system board, I need to also make sure that “Secure Boot” is disabled in BIOS menu.&lt;br /&gt;
Otherwise it will not allow the OpenSUSE TW to boot. It didn’t for me because my Secure Boot was enabled.&lt;br /&gt;
So, I had to disable it. And &lt;em&gt;then&lt;/em&gt; it worked.&lt;br /&gt;
After first successful boot, I think I can enable it again.)&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this process is my own making.&lt;br /&gt;
The whole credit goes to this very useful demo - &lt;a href=&quot;https://youtu.be/6L3i4Zgb8Y8?si=D96jkLbSR1Dzr416&quot;&gt;How To Fix Grub in OpenSUSE | UEFI (KMDTech)&lt;/a&gt; (Thank you!)&lt;br /&gt;
It worked twice for me without a single hiccup.&lt;br /&gt;
(but ofcourse, if you need to follow, please do it carefully, after checking, cross-checking and understanding everything you’re typing.)&lt;/p&gt;</description>
	<pubDate>Sun, 02 Nov 2025 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Priyanka Saggu: Setup (again): HP Laser MFP 136nw</title>
	<guid isPermaLink="true">https://psaggu.com/2025/11/01/hp-printer-setup.html</guid>
	<link>https://psaggu.com/2025/11/01/hp-printer-setup.html</link>
	<description>&lt;p&gt;A few weeks back, I had to reset my router for firmware updates.&lt;/p&gt;

&lt;p&gt;And because of that, some devices on my local network, in this case my HP printer stopped working on Wi-Fi.&lt;/p&gt;

&lt;p&gt;I followed the following steps today, to make it work again.&lt;br /&gt;
(&lt;a href=&quot;https://janusworx.com&quot;&gt;MJB&lt;/a&gt; helped lots! Thank you so much! Very grateful!)&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;I realised the IP (http://192.168.1.z) that was assigned to my HP Printer (before router reset) is now taken by some other device on my local network because of DHCP dynamically assigning IPs.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;I connect to the HP Printer via Ethernet, access the HP Printer configuration page on the last assigned IP (http://192.168.1.z).
(Because now I am connected to the HP Printer via Ethernet, the router give preference to the HP Printer on the above IP, even though DHCP Server had assigned this IP to another device on my network.)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;I login to my HP Printer configuration page.&lt;br /&gt;
I go to “Settings &amp;gt; Network Settings &amp;gt; Wi-Fi”.&lt;br /&gt;
On this menu page, click on “Wi-Fi Settings &amp;gt; Advanced Settings &amp;gt; Network Setup”.&lt;br /&gt;
Go to “SSID” and hit “Search List” and “Refresh”.&lt;br /&gt;
From the drop down, pick the Wi-Fi SSID I want to connect to, at the bottom, pick “Network Key Setup” and put the updated SSID password in there (both in “Network Key” and “Confirm Network Key”).&lt;br /&gt;
Don’t forget to hit “Apply”.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Now other thing I have to fix is that the IP address is still assigned by the Router’s DHCP server to another device on LAN.&lt;br /&gt;
I need to assign a proper IP to my HP Printer outside the range of IPs available to DHCP server to assign to devices dynamically.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;For that, go to the Router admin page, login and go to “Local Network &amp;gt; LAN &amp;gt; IPv4”.&lt;br /&gt;
Then go to the section “DHCP Server” and change “DHCP Start IP Address” and “DHCP End IP Address” respectively to some “192.168.1.a” and “192.168.1.b” and hit “Apply”.&lt;br /&gt;
With this the router will now have IP “192.168.1.a-1” and DHCP server will only be able to assign dynamically IPs to devices within the assigned pool only.&lt;br /&gt;
(with this, what I am trying is to limit the pool of IPs available to DHCP server so that I can assign an IP (“192.168.1.b+1”) to HP Printer outside the limits of this available DHCP server IP pool manually. So, that the printer IP doesn’t conflict with any other device IP assigned by DHCP server.)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Now login back to the Printer configuration page,  go to “Settings &amp;gt; Network Settings &amp;gt; TCP/IPv4”.&lt;br /&gt;
Here, in the “General” section, pick “Manual” under the “Assign IPv4 Address” option.&lt;br /&gt;
And manually assign the following - (1) “IPv4 Address: 192.168.1.b+1”, (2) “Subnet Mask: 255.255.255.0”, and (3) “Gateway Address: 192.168.1.a-1” (should match the router IP address) to HP Printer.&lt;br /&gt;
And hit “Apply”.&lt;br /&gt;
With this, the HP Printer configuration page itself will reload to the new assigned IP address url (http://192.168.1.b+1).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;After above steps, I then remove the Ethernet from the HP Printer, restart it.&lt;br /&gt;
And check if I am still able to access the HP Printer on the assigned IP via Wi-Fi (http://192.168.1.b+1).&lt;br /&gt;
Yes! It worked now!&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Then now I need to test, whether printing works on Wi-Fi.&lt;br /&gt;
I am on an OpenSUSE Tumbleweed machine.&lt;br /&gt;
I go to the “Settings &amp;gt; Printers” page.&lt;br /&gt;
I have to make sure that my printer is showing up there.&lt;br /&gt;
(It wasn’t before, I had to once manually add a printer and pick up the latest available matching model from the available database, but that’s not needed after my steps below.)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Yes, printer shows up. I gave a test print job. Printing on Wi-Fi is working now.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;But Scanning still doesn’t work. Neither on Wifi, nor on Ethernet.&lt;br /&gt;
My system just doesn’t detect the scanner on my HP Printer at all.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Now, I go back to HP Printer configuration page (http://192.168.1.b+1).&lt;br /&gt;
Go to “Settings &amp;gt; Network Settings” and ensure that “AirPrint” and “Bonjour(mDNS)” both are enabled.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Now, I need to do a few things at the OS level.&lt;br /&gt;
Install (or ensure if already installed) the following set of packages.&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# install required packages 
  
sudo zypper install avahi avahi-utils nss-mdns
sudo zypper install hplip hplip-sane sane-backends
sudo zypper install sane-airscan ipp-usb

# enable, start and verify status of avahi daeomon (make sure I use `-l` flag to have all available information from the service status output)

sudo systemctl enable avahi-daemon
sudo systemctl start avahi-daemon
sudo systemctl status -l avahi-daemon.service

# make sure I have all avahi-related tools as well
  
which avahi-browse
which avahi-resolve
which avahi-publish
rpm -ql avahi | grep bin # gives me `/usr/sbin/avahi-daemon` and `/usr/sbin/avahi-dnsconfd`


# ensure firewall is allowing mdns and ipp

sudo firewall-cmd --permanent --add-service=mdns
sudo firewall-cmd --permanent --add-service=ipp
sudo firewall-cmd --reload
sudo firewall-cmd --info-service=mdns
sudo firewall-cmd --info-service=ipp

# and restart firewall
  
sudo systemctl restart firewalld
sudo systemctl status -l firewalld

# now check if avahi-browse can see devices advertised by my HP Printer

avahi-browse -a | grep HP
## output something like following. I need to make sure it has `_scanner._tcp` and `_uscan._tcp` showing up
  + wlp0s20f3 IPv4 HP Laser MFP 136nw (xx:xx:xx)                 _ipp._tcp            local
  + wlp0s20f3 IPv4 HP Laser MFP 136nw (xx:xx:xx)                 _scanner._tcp        local
  + wlp0s20f3 IPv4 HP Laser MFP 136nw (xx:xx:xx)                 _uscan._tcp          local
  + wlp0s20f3 IPv4 HP Laser MFP 136nw (xx:xx:xx)                 _uscans._tcp         local
  + wlp0s20f3 IPv4 HP Laser MFP 136nw (xx:xx:xx)                 _http._tcp           local
  + wlp0s20f3 IPv4 HP Laser MFP 136nw (xx:xx:xx)                 _pdl-datastream._tcp local
  + wlp0s20f3 IPv4 HP Laser MFP 136nw (xx:xx:xx)                 _printer._tcp        local
  + wlp0s20f3 IPv4 HP Laser MFP 136nw (xx:xx:xx)                 _http-alt._tcp       local
  + wlp0s20f3 IPv4 HP Laser MFP 136nw (xx:xx:xx)                 _privet._tcp         local

# if device shows up, then check is scanner is responding on the network

ping -c3 192.168.1.x

curl http://192.168.1.x:8080/eSCL # any xml ouput is fine as long as there's something

# final check
  
scanimage -L
## it should list something like:
device `airscan:xx:xx Laser MFP 136nw (xx:xx:xx)' is a eSCL HP Laser MFP 136nw (xx:xx:xx) ip=192.168.1.x
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;At this point, the “Scan Documents” app should be detecting the scanner on my HP printer (it did!)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Also, with Avahi working, my OS system “Settings &amp;gt; Printers” also got a HP Printer added automatically with the correct model name etc.&lt;br /&gt;
(Scanner also, although that doesn’t show up as a menu item in the system settings.)&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;</description>
	<pubDate>Sat, 01 Nov 2025 00:00:00 +0000</pubDate>
</item>
<item>
	<title>Sanyam Khurana: Reflections of a Wandering Soul</title>
	<guid isPermaLink="false">tag:www.sanyamkhurana.com,2025-10-24:/blog/reflections-of-a-wandering-soul.html</guid>
	<link>https://www.sanyamkhurana.com/blog/reflections-of-a-wandering-soul.html</link>
	<description>&lt;p class=&quot;first last&quot;&gt;A collection of four poems reflecting on resilience, solitude, hope, and authenticity in the face of life's challenges.&lt;/p&gt;</description>
	<pubDate>Fri, 24 Oct 2025 10:52:00 +0000</pubDate>
</item>
<item>
	<title>Anwesha Das: ssh version output in stderr</title>
	<guid isPermaLink="false">https://anweshadas.in/rss/68ec16c641dcec000189c60b</guid>
	<link>http://anweshadas.in/ssh-version-output-in-stderr/</link>
	<description>&lt;p&gt;Generally Linux commands print their version on &lt;code&gt;stdout&lt;/code&gt;, for example&lt;br /&gt;
&lt;code&gt;git --version&lt;/code&gt;  or &lt;code&gt;python --version&lt;/code&gt;.  But not &lt;code&gt;ssh&lt;/code&gt;. &lt;code&gt;ssh -V&lt;/code&gt; prints output  to &lt;code&gt;stderr&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To test it you can do the following:&lt;/p&gt;
&lt;h3 id=&quot;git-version-on-stdout&quot;&gt;git version on stdout&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; git --version 2&amp;gt; error 1&amp;gt; output 
&amp;gt; cat output
git version 2.51.0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;ssh-version-on-stderr&quot;&gt;ssh version on stderr&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; ssh -V 2&amp;gt;&amp;gt; error 1&amp;gt;&amp;gt; output
&amp;gt; cat error
OpenSSH_9.9p1, OpenSSL 3.2.4 11 Feb 2025
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hope this will be helpful.&lt;/p&gt;</description>
	<pubDate>Sun, 12 Oct 2025 21:01:13 +0000</pubDate>
</item>
<item>
	<title>Anwesha Das: Joy of automation</title>
	<guid isPermaLink="false">https://anweshadas.in/rss/68867f6e41dcec000189c5e3</guid>
	<link>http://anweshadas.in/joy-of-automation/</link>
	<description>&lt;p&gt;After 145+ commits spread over &lt;a href=&quot;https://github.com/ansible-community/ansible-build-data/pull/265?ref=anweshadas.in&quot;&gt;multiple&lt;/a&gt; &lt;a href=&quot;https://github.com/ansible/ansible-documentation/pull/121?ref=anweshadas.in&quot;&gt;PRs&lt;/a&gt;, 450+ conversations and feedback, and accountable communication via several different communication mediums spanning over 2 years, the Ansible Release Management is finally completely automated, using GitHub Actions.  When I joined Red Hat in November 2022, I was tasked with releasing the Ansible Community Package.&lt;/p&gt;
&lt;p&gt;The first hurdle I faced was that there was no documented release process. What we had were release managers&amp;amp;apos private notes. It was over in personal repositories, internal Red Hat Google Docs, and personal code. Since all those past release managers left the organization (apart from one), it was very difficult to gather and figure out what, why, and how the release process worked. I had one supporter, my trainer (the then-release manager), Christian. He shared with me his notes and the steps he followed. He guided me on how he did the release.&lt;/p&gt;
&lt;p&gt;Now we have a community release managers working group where contributors from the community also take part and release Ansible. And we have the two aforementioned GitHub actions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;First one builds the package and also opens a PR to the repository, and then waits for human input.&lt;/li&gt;
&lt;li&gt;Meanwhile, the release manager can use the second action to create another PR to the Ansible documentation repository from the updated porting guide from the first PR.&lt;/li&gt;
&lt;li&gt;After the PRs are approved, the release manager can continue with the first action and release the Ansible wheel package and the source tarball to &lt;a href=&quot;https://pypi.org/?ref=anweshadas.in&quot;&gt;PyPI&lt;/a&gt; in a fully automated way using &lt;a href=&quot;https://docs.pypi.org/trusted-publishers/?ref=anweshadas.in&quot;&gt;trusted publishing&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I would like to thank &lt;a href=&quot;https://www.linkedin.com/in/felixfontein/?ref=anweshadas.in&quot;&gt;Felix&lt;/a&gt;, &lt;a href=&quot;https://floss.social/@maxgot?ref=anweshadas.in&quot;&gt;Gotmax&lt;/a&gt; and &lt;a href=&quot;https://github.com/webknjaz?ref=anweshadas.in&quot;&gt;Sviatoslav&lt;/a&gt; for feedback during the journey, thank you.&lt;/p&gt;
&lt;p&gt;Many say automation is bad. In many companies, management gets the wrong idea that, when good automation is in place, they can fire senior engineers and get interns or inexperienced people to get the job done. That works till something breaks down. The value of experience comes when we have to fix things in automation. Automation enables new folks to get introduced to things, and enables experienced folks to work on other things.&lt;/p&gt;</description>
	<pubDate>Sun, 27 Jul 2025 22:42:59 +0000</pubDate>
</item>
<item>
	<title>Titas Dey: Arrow Function vs Regular Function in JavaScript</title>
	<guid isPermaLink="true">https://blogs.dgplug.org/titas/arrow-function-vs-regular-function-in-javascript</guid>
	<link>https://blogs.dgplug.org/titas/arrow-function-vs-regular-function-in-javascript</link>
	<description>&lt;h2 id=&quot;arrow-function-vs-regular-function-in-javascript&quot;&gt;Arrow Function vs Regular Function in JavaScript&lt;/h2&gt;

&lt;p&gt;Yeah, everyone already knows the syntax is different. No need to waste time on that.&lt;/p&gt;

&lt;p&gt;Let’s look at what actually &lt;em&gt;matters&lt;/em&gt; — how they behave differently.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;1-arguments&quot;&gt;1. &lt;code&gt;arguments&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Regular functions come with this built-in thing called &lt;code&gt;arguments&lt;/code&gt; object. Even if you don’t define any parameters, you can still access whatever got passed when the function was called.&lt;/p&gt;

&lt;p&gt;Arrow functions? Nope. No &lt;code&gt;arguments&lt;/code&gt; object. Try using it, and it’ll just throw an error.&lt;/p&gt;

&lt;h4 id=&quot;regular-function&quot;&gt;Regular function:&lt;/h4&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function test() {
  console.log(arguments);
}

test(1, &quot;hello world&quot;, true); 
// o/p
// { '0': 1, '1': 'hello world', '2': true }
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&quot;arrow-function&quot;&gt;Arrow function:&lt;/h4&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const test = () =&amp;gt; {
  console.log(arguments); 
};

test(1, &quot;hello world&quot;, true); // Throws ReferenceError

&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;2-return&quot;&gt;2. &lt;code&gt;return&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Arrow functions have implicit return but regular functions don't.
i.e We can return the result automatically if we write it in a single line , inside a parenthesis in arrow functions. Regular functions always require the &lt;code&gt;return&lt;/code&gt; keyword.&lt;/p&gt;

&lt;h4 id=&quot;regular-function-1&quot;&gt;Regular function:&lt;/h4&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;function add(a, b) {
 const c = a + b;
}

console.log(add(5, 10)); // o/p : undefined 
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&quot;arrow-function-1&quot;&gt;Arrow function:&lt;/h4&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const add = (a, b) =&amp;gt; (a + b);

console.log(add(5, 10)); // o/p : 15
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;3-this&quot;&gt;3. &lt;code&gt;this&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Arrow functions do not have their own this binding. Instead, they lexically inherit this from the surrounding (parent) scope at the time of definition. This means the value of this inside an arrow function is fixed and cannot be changed using .call(), .apply(), or .bind().&lt;/p&gt;

&lt;p&gt;Regular functions, on the other hand, have dynamic this binding — it depends on how the function is invoked. When called as a method, this refers to the object; when called standalone, this can be undefined (in strict mode) or refer to the global object (in non-strict mode).&lt;/p&gt;

&lt;p&gt;Because of this behavior, arrow functions are commonly used in cases where you want to preserve the outer this context, such as in callbacks or within class methods that rely on this from the class instance.&lt;/p&gt;

&lt;h4 id=&quot;regular-function-2&quot;&gt;Regular function :&lt;/h4&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const obj = {
  name: &quot;Titas&quot;,
  sayHi: function () {
    console.log(this.name);
  }
};

obj.sayHi(); // o/p : Titas
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&quot;arrow-function-2&quot;&gt;Arrow function :&lt;/h4&gt;

&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const obj = {
  name: &quot;Titas&quot;,
  sayHi: () =&amp;gt; {
    console.log(this.name);
  }
};

obj.sayHi(); // o/p :  undefined
&lt;/code&gt;&lt;/pre&gt;

&lt;hr /&gt;

&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;print(&quot;Titas signing out !&quot;)
&lt;/code&gt;&lt;/pre&gt;</description>
	<pubDate>Wed, 23 Jul 2025 19:20:14 +0000</pubDate>
</item>
<item>
	<title>Sandeep Choudhary: Debugging maxlocksper_transaction: A Journey into Pytest Parallelism</title>
	<guid isPermaLink="true">https://blogs.dgplug.org/sandeepk/debugging-max_locks_per_transaction-a-journey-into-pytest-parallelism</guid>
	<link>https://blogs.dgplug.org/sandeepk/debugging-max_locks_per_transaction-a-journey-into-pytest-parallelism</link>
	<description>&lt;p&gt;So I was fixing some slow tests, and whenever I ran them through the &lt;code&gt;pytest&lt;/code&gt; command, I was greeted with the dreaded &lt;code&gt;max_locks_per_transaction&lt;/code&gt; error.&lt;/p&gt;

&lt;p&gt;My first instinct? Just crank up the &lt;code&gt;max_locks_per_transaction&lt;/code&gt; from 64 to 1024.&lt;/p&gt;

&lt;p&gt;But... that didn’t feel right. I recreate my DB frequently, which means I’d have to set that value again and again. It felt like a hacky workaround rather than a proper solution.&lt;/p&gt;

&lt;p&gt;Then, like any developer, I started digging around — first checking the Confluence page for dev docs to see if anyone else had faced this issue. No luck. Then I moved to Slack, and that’s where I found this command someone had shared:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;pytest -n=0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This was new to me. So, like any sane dev in 2025, I asked ChatGPT what this was about. That’s how I came across &lt;code&gt;pytest-xdist&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;what-is-pytest-xdist&quot;&gt;What is &lt;code&gt;pytest-xdist&lt;/code&gt;?&lt;/h2&gt;

&lt;blockquote&gt;&lt;p&gt;The &lt;code&gt;pytest-xdist&lt;/code&gt; plugin extends pytest with new test execution modes — the most common one is distributing tests across multiple CPUs to &lt;strong&gt;speed up test execution&lt;/strong&gt;.&lt;/p&gt;&lt;/blockquote&gt;

&lt;h2 id=&quot;what-does-pytest-xdist-do&quot;&gt;What does &lt;code&gt;pytest-xdist&lt;/code&gt; do?&lt;/h2&gt;

&lt;blockquote&gt;&lt;p&gt;Runs tests in &lt;strong&gt;parallel&lt;/strong&gt; using &lt;code&gt;&amp;lt;numprocesses&amp;gt;&lt;/code&gt; workers (Python processes), which is a game changer when:
– You have a large test suite&lt;br /&gt;
– Each test takes a significant amount of time&lt;br /&gt;
– Your tests are independent (i.e., no shared global state)&lt;/p&gt;&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;p&gt;That’s pretty much it — I plugged in &lt;code&gt;pytest -n=0&lt;/code&gt; and boom, no more transaction locks errors.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

&lt;p&gt;References
– &lt;a href=&quot;https://pytest-xdist.readthedocs.io/en/stable/&quot; rel=&quot;nofollow&quot;&gt;https://pytest-xdist.readthedocs.io/en/stable/&lt;/a&gt;
– &lt;a href=&quot;https://docs.pytest.org/en/stable/reference/reference.html&quot; rel=&quot;nofollow&quot;&gt;https://docs.pytest.org/en/stable/reference/reference.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;hashtag&quot; href=&quot;https://blogs.dgplug.org/sandeepk/tag:pytest&quot; rel=&quot;nofollow&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;span class=&quot;p-category&quot;&gt;pytest&lt;/span&gt;&lt;/a&gt; &lt;a class=&quot;hashtag&quot; href=&quot;https://blogs.dgplug.org/sandeepk/tag:Python&quot; rel=&quot;nofollow&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;span class=&quot;p-category&quot;&gt;Python&lt;/span&gt;&lt;/a&gt; &lt;a class=&quot;hashtag&quot; href=&quot;https://blogs.dgplug.org/sandeepk/tag:chatgpt&quot; rel=&quot;nofollow&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;span class=&quot;p-category&quot;&gt;chatgpt&lt;/span&gt;&lt;/a&gt; &lt;a class=&quot;hashtag&quot; href=&quot;https://blogs.dgplug.org/sandeepk/tag:debugging&quot; rel=&quot;nofollow&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;span class=&quot;p-category&quot;&gt;debugging&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</description>
	<pubDate>Wed, 16 Jul 2025 17:07:59 +0000</pubDate>
</item>
<item>
	<title>Titas Dey: I'm cooked</title>
	<guid isPermaLink="true">https://blogs.dgplug.org/titas/im-cooked</guid>
	<link>https://blogs.dgplug.org/titas/im-cooked</link>
	<description>&lt;p&gt;The college is really gonna teach us Data Structures and Algorithms in C . And make me write 100 line codes in paper for lab manuals .&lt;/p&gt;</description>
	<pubDate>Fri, 11 Jul 2025 19:19:48 +0000</pubDate>
</item>
<item>
	<title>Anwesha Das: Creating Pull request with GitHub Action</title>
	<guid isPermaLink="false">https://anweshadas.in/rss/686ab0ec41dcec000189c58c</guid>
	<link>http://anweshadas.in/creating-pull-request-with-github-action/</link>
	<description>&lt;pre&gt;&lt;code class=&quot;language-YAML&quot;&gt;---
name: Testing Gha
on:
  workflow_dispatch:
    inputs:
      GIT_BRANCH:
        description: The git branch to be worked on
        required: true

jobs:
  test-pr-creation:
    name: Creates test PR
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
      contents: write
    env:
      GIT_BRANCH: ${{ inputs.GIT_BRANCH }}
    steps:
      - uses: actions/checkout@v4
      - name: Updates README
        run: echo date &amp;gt;&amp;gt; README.md

      - name: Set up git
        run: |
          git switch --create &quot;${GIT_BRANCH}&quot;
          ACTOR_NAME=&quot;$(curl -s https://api.github.com/users/&quot;${GITHUB_ACTOR}&quot; | jq --raw-output &amp;amp;apos.name // .login&amp;amp;apos)&quot;
          git config --global user.name &quot;${ACTOR_NAME}&quot;
          git config --global user.email &quot;${GITHUB_ACTOR_ID}+${GITHUB_ACTOR}@users.noreply.github.com&quot;

      - name: Add README
        run: git add README.md

      - name: Commit
        run: &amp;gt;-
          git diff-index --quiet HEAD ||
          git commit -m &quot;test commit msg&quot;
      - name: Push to the repo
        run: git push origin &quot;${GIT_BRANCH}&quot;

      - name: Create PR as draft
        env:
          GITHUB_TOKEN: ${{ github.token }}
        run: &amp;gt;-
          gh pr create
          --draft
          --base main
          --head &quot;${GIT_BRANCH}&quot;
          --title &quot;test commit msg&quot;
          --body &quot;pr body&quot;

      - name: Retrieve the existing PR URL
        id: existing-pr
        env:
          GITHUB_TOKEN: ${{ github.token }}
        run: &amp;gt;
          echo -n pull_request_url= &amp;gt;&amp;gt; &quot;${GITHUB_OUTPUT}&quot;

          gh pr view
          --json &amp;amp;aposurl&amp;amp;apos
          --jq &amp;amp;apos.url&amp;amp;apos
          --repo &amp;amp;apos${{ github.repository }}&amp;amp;apos
          &amp;amp;apos${{ env.GIT_BRANCH }}&amp;amp;apos
          &amp;gt;&amp;gt; &quot;${GITHUB_OUTPUT}&quot;
      - name: Select the actual PR URL
        id: pr
        env:
          GITHUB_TOKEN: ${{ github.token }}
        run: &amp;gt;
          echo -n pull_request_url=
          &amp;gt;&amp;gt; &quot;${GITHUB_OUTPUT}&quot;

          echo &amp;amp;apos${{steps.existing-pr.outputs.pull_request_url}}&amp;amp;apos
          &amp;gt;&amp;gt; &quot;${GITHUB_OUTPUT}&quot;

      - name: Log the pull request details
        run: &amp;gt;-
           echo &amp;amp;aposPR URL: ${{ steps.pr.outputs.pull_request_url }}&amp;amp;apos | tee -a &quot;${GITHUB_STEP_SUMMARY}&quot;


      - name: Instruct the maintainers to trigger CI by undrafting the PR
        env:
          GITHUB_TOKEN: ${{ github.token }}
        run: &amp;gt;-
            gh pr comment
            --body &amp;amp;aposPlease mark the PR as ready for review to trigger PR checks.&amp;amp;apos
            --repo &amp;amp;apos${{ github.repository }}&amp;amp;apos
            &amp;amp;apos${{ steps.pr.outputs.pull_request_url }}&amp;amp;apos
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above is an example of how to create a &lt;code&gt;draft PR&lt;/code&gt; via GitHub Actions. We need to give permissions to the GitHub action to create PR in a repository (&lt;code&gt;workflow permissions&lt;/code&gt; in the settings).&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;workflow_permissions.png&quot; src=&quot;http://anweshadas.in/content/images/2025/07/workflow_permissions.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Hopefully, this blogpost will help my future self.&lt;/p&gt;</description>
	<pubDate>Sun, 06 Jul 2025 18:22:04 +0000</pubDate>
</item>
<item>
	<title>Sandeep Choudhary: ChatGPT and Images</title>
	<guid isPermaLink="true">https://blogs.dgplug.org/sandeepk/chatgpt-and-images</guid>
	<link>https://blogs.dgplug.org/sandeepk/chatgpt-and-images</link>
	<description>&lt;p&gt;I’ve been working on a few side projects and using ChatGPT for ideation and brainstorming around ideas and features for the MVP. As part of this, I needed a logo for my app. Naturally, I turned to AI to help me generate one.&lt;/p&gt;

&lt;p&gt;However, I noticed that when generating images, ChatGPT doesn’t always follow the guidelines perfectly. Each time I asked for a new version, it would create a completely different image, which made it difficult to iterate or make small tweaks.&lt;/p&gt;

&lt;p&gt;But I found a better way.&lt;/p&gt;

&lt;p&gt;Instead of generating a brand new image every time, I first explained my app idea and the name. ChatGPT generated an image I liked.&lt;/p&gt;

&lt;p&gt;So I asked ChatGPT to generate the JSON for the image instead. I then manually tweaked the JSON file to adjust things exactly the way I wanted. When I asked ChatGPT to generate the image based on the updated JSON, it finally created the image as per my request — no random changes, just the specific adjustments I needed.&lt;/p&gt;

&lt;h3 id=&quot;exploration-phase&quot;&gt;Exploration Phase&lt;/h3&gt;

&lt;p&gt;&lt;img alt=&quot;SplitX logo&quot; src=&quot;https://raw.githubusercontent.com/Skchoudhary/blog-asset/master/dgplug-blog/slpitX_icon_with_text.png&quot; /&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;image&quot;: {
    &quot;file_name&quot;: &quot;splitX_icon_with_text.png&quot;,
    &quot;background_color&quot;: &quot;black&quot;,
    &quot;elements&quot;: [
      {
        &quot;type&quot;: &quot;text&quot;,
        &quot;content&quot;: &quot;SplitX&quot;,
        &quot;font_style&quot;: &quot;bold&quot;,
        &quot;font_color&quot;: &quot;white&quot;,
        &quot;position&quot;: &quot;center&quot;,
        &quot;font_size&quot;: &quot;large&quot;
      },
      {
        &quot;type&quot;: &quot;shape&quot;,
        &quot;shape_type&quot;: &quot;X&quot;,
        &quot;style&quot;: &quot;geometric split&quot;,
        &quot;colors&quot;: [
          {
            &quot;section&quot;: &quot;top-left&quot;,
            &quot;gradient&quot;: [&quot;#FF4E50&quot;, &quot;#F9D423&quot;]
          },
          {
            &quot;section&quot;: &quot;bottom-left&quot;,
            &quot;gradient&quot;: [&quot;#F9D423&quot;, &quot;#FC913A&quot;]
          },
          {
            &quot;section&quot;: &quot;top-right&quot;,
            &quot;gradient&quot;: [&quot;#24C6DC&quot;, &quot;#514A9D&quot;]
          },
          {
            &quot;section&quot;: &quot;bottom-right&quot;,
            &quot;gradient&quot;: [&quot;#514A9D&quot;, &quot;#E55D87&quot;]
          }
        ],
        &quot;position&quot;: &quot;center behind text&quot;,
        &quot;style_notes&quot;: &quot;Each quadrant of the X has a distinct gradient, giving a modern and vibrant look. The X is split visually in the middle, aligning with the 'Split' theme.&quot;
      }
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;final-design&quot;&gt;Final Design&lt;/h3&gt;

&lt;p&gt;&lt;img alt=&quot;SplitX logo&quot; src=&quot;https://raw.githubusercontent.com/Skchoudhary/blog-asset/master/dgplug-blog/ChatGPT%20Image%20Jul%201,%202025,%2011_07_23%20PM.png&quot; /&gt;
Updated JSON&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;image&quot;: {
    &quot;file_name&quot;: &quot;splitX_icon_with_text.png&quot;,
    &quot;background_color&quot;: &quot;transparent&quot;,
    &quot;elements&quot;: [
      {
        &quot;type&quot;: &quot;shape&quot;,
        &quot;shape_type&quot;: &quot;X&quot;,
        &quot;style&quot;: &quot;geometric split&quot;,
        &quot;colors&quot;: [
          {
            &quot;section&quot;: &quot;top-left&quot;,
            &quot;gradient&quot;: [
              &quot;#FF4E50&quot;,
              &quot;#F9D423&quot;
            ]
          },
          {
            &quot;section&quot;: &quot;bottom-left&quot;,
            &quot;gradient&quot;: [
              &quot;#F9D423&quot;,
              &quot;#FC913A&quot;
            ]
          },
          {
            &quot;section&quot;: &quot;top-right&quot;,
            &quot;gradient&quot;: [
              &quot;#24C6DC&quot;,
              &quot;#514A9D&quot;
            ]
          },
          {
            &quot;section&quot;: &quot;bottom-right&quot;,
            &quot;gradient&quot;: [
              &quot;#514A9D&quot;,
              &quot;#E55D87&quot;
            ]
          }
        ],
        &quot;position&quot;: &quot;center &quot;,
        &quot;style_notes&quot;: &quot;Each quadrant of the X has a distinct gradient, giving a modern and vibrant look. The X is split visually in the middle, aligning with the 'Split' theme.&quot;
      }
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you want to tweak or refine an image, first generate the JSON, make your changes there, and then ask ChatGPT to generate the image using your updated JSON. This gives you much more control over the final result.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

&lt;p&gt;P.S. Feel free to check out the app — it's live now at &lt;a href=&quot;https://splitx.org/&quot; rel=&quot;nofollow&quot;&gt;https://splitx.org/&lt;/a&gt;. Would love to hear what you think!&lt;/p&gt;</description>
	<pubDate>Thu, 03 Jul 2025 13:28:47 +0000</pubDate>
</item>

</channel>
</rss>
