<?xml version="1.0" encoding="UTF-8" ?> <?xml-stylesheet type="text/xsl" href="rss.xsl"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/"> <channel> <title>Muhammad Ibtisam | Engineering Blog</title><description>Practical engineering write-ups on infrastructure, containers, and distributed systems. Every post comes from a real setup: no theory without execution.</description><link>https://blog.ibtisam-iq.com/</link><atom:link href="https://blog.ibtisam-iq.com/feed_rss_created.xml" rel="self" type="application/rss+xml" /> <managingEditor>Muhammad Ibtisam</managingEditor><language>en</language> <pubDate>Thu, 01 Oct 2026 00:18:01 -0000</pubDate> <lastBuildDate>Thu, 01 Oct 2026 00:18:01 -0000</lastBuildDate> <ttl>1440</ttl> <generator>MkDocs RSS plugin - v1.19.0</generator> <image> <url>https://blog.ibtisam-iq.com/images/favicon.png</url> <title>Muhammad Ibtisam | Engineering Blog</title> <link>https://blog.ibtisam-iq.com/</link> </image> <item> <title>I Gave Hyperagent One Handle and Nothing Else: It Verified the Rest</title> <author>Muhammad Ibtisam</author> <category>Career</category> <category>Career &amp; Growth</category> <category>DevOps</category> <category>Documentation</category> <description>&lt;h1&gt;I Gave Hyperagent One Handle and Nothing Else: It Verified the Rest&lt;/h1&gt; &lt;p&gt;Not my name, not a CV, not a list of my sites. Six words containing a GitHub handle, typed into an empty account. It came back with seven live subdomains, more than thirty repositories, two certification badges, a Docker Hub namespace and a tutorial on somebody else&#39;s platform, every claim graded against an independent source. Twice, a day apart, for $21.02.&lt;/p&gt;</description> <link>https://blog.ibtisam-iq.com/ai-agent-audit-devops-portfolio/</link> <pubDate>Tue, 04 Aug 2026 00:00:00 +0000</pubDate> <source url="https://blog.ibtisam-iq.com/feed_rss_created.xml">Muhammad Ibtisam | Engineering Blog</source><guid isPermaLink="true">https://blog.ibtisam-iq.com/ai-agent-audit-devops-portfolio/</guid> <enclosure url="https://blog.ibtisam-iq.com/assets/images/social/ai-agent-audit-devops-portfolio.png" type="image/png" length="77358" /> </item> <item> <title>My Builds Were Reproducible, So My Deployments Stopped</title> <author>Muhammad Ibtisam</author> <category>ArgoCD</category> <category>BuildKit</category> <category>CI/CD &amp; Automation</category> <category>Debugging</category> <category>Docker</category> <category>GitOps</category> <category>Kubernetes</category> <description>&lt;h1&gt;My Builds Were Reproducible, So My Deployments Stopped&lt;/h1&gt; &lt;p&gt;Ten microservices on EKS, images landing in the registry on every push, and a controller whose entire job is to notice new images and roll the pods. It noticed nothing. No errors, no warnings, just a log line reporting that it had considered ten images and updated zero of them.&lt;/p&gt; &lt;p&gt;The cause turned out to be a feature working correctly in one tool making another tool&#39;s core assumption false.&lt;/p&gt;</description> <link>https://blog.ibtisam-iq.com/buildkit-epoch-broke-image-updater/</link> <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate> <source url="https://blog.ibtisam-iq.com/feed_rss_created.xml">Muhammad Ibtisam | Engineering Blog</source><guid isPermaLink="true">https://blog.ibtisam-iq.com/buildkit-epoch-broke-image-updater/</guid> <enclosure url="https://blog.ibtisam-iq.com/assets/images/social/buildkit-epoch-broke-image-updater.png" type="image/png" length="89561" /> </item> <item> <title>Push or Pull: Two Ways to Hand Off a Deployment</title> <author>Muhammad Ibtisam</author> <category>Architecture</category> <category>ArgoCD</category> <category>CI/CD</category> <category>CI/CD &amp; Automation</category> <category>GitHub Actions</category> <category>GitOps</category> <category>Kubernetes</category> <description>&lt;h1&gt;Push or Pull: Two Ways to Hand Off a Deployment&lt;/h1&gt; &lt;p&gt;I built the same handoff twice, in opposite directions. In three monolith pipelines, CI ends by committing an image tag into the deployment repository. For ten microservices, CI stops at the registry and a controller notices. Both are GitOps. Only one of them survived ten services.&lt;/p&gt;</description> <link>https://blog.ibtisam-iq.com/gitops-push-vs-pull-handoff/</link> <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate> <source url="https://blog.ibtisam-iq.com/feed_rss_created.xml">Muhammad Ibtisam | Engineering Blog</source><guid isPermaLink="true">https://blog.ibtisam-iq.com/gitops-push-vs-pull-handoff/</guid> <enclosure url="https://blog.ibtisam-iq.com/assets/images/social/gitops-push-vs-pull-handoff.png" type="image/png" length="77543" /> </item> <item> <title>Building Only What Changed, and the Permissions Ceiling Nobody Warns You About</title> <author>Muhammad Ibtisam</author> <category>Automation</category> <category>CI/CD</category> <category>CI/CD &amp; Automation</category> <category>Debugging</category> <category>GitHub Actions</category> <category>Monorepo</category> <description>&lt;h1&gt;Building Only What Changed, and the Permissions Ceiling Nobody Warns You About&lt;/h1&gt; &lt;p&gt;Ten services in one repository. Most commits touch one of them. Rebuilding all ten on every push is the default and it is wrong, so the pipeline detects which service directories changed and fans out one job per service.&lt;/p&gt; &lt;p&gt;Two things about that turned out to be harder than the idea: computing &#34;what changed&#34; correctly across every way a workflow can be triggered, and discovering that a reusable workflow cannot ask for permissions its caller did not grant.&lt;/p&gt;</description> <link>https://blog.ibtisam-iq.com/monorepo-matrix-dispatch-permissions/</link> <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate> <source url="https://blog.ibtisam-iq.com/feed_rss_created.xml">Muhammad Ibtisam | Engineering Blog</source><guid isPermaLink="true">https://blog.ibtisam-iq.com/monorepo-matrix-dispatch-permissions/</guid> <enclosure url="https://blog.ibtisam-iq.com/assets/images/social/monorepo-matrix-dispatch-permissions.png" type="image/png" length="83890" /> </item> <item> <title>The Jenkinsfile Rewrite Was Mostly Deletions</title> <author>Muhammad Ibtisam</author> <category>Architecture</category> <category>CI/CD</category> <category>CI/CD &amp; Automation</category> <category>Jenkins</category> <category>Maven</category> <category>SonarQube</category> <description>&lt;h1&gt;The Jenkinsfile Rewrite Was Mostly Deletions&lt;/h1&gt; &lt;p&gt;I rewrote a working Jenkins pipeline. The version that replaced it is longer, and the changes that mattered most were the two blocks I removed.&lt;/p&gt; &lt;p&gt;Both of them did the same thing: they asked the Jenkins server to supply something the pipeline needed. Taking them out is what made the file portable, and it is the single change I would make first to any Jenkinsfile I inherited.&lt;/p&gt;</description> <link>https://blog.ibtisam-iq.com/why-i-rewrote-my-jenkinsfile/</link> <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate> <source url="https://blog.ibtisam-iq.com/feed_rss_created.xml">Muhammad Ibtisam | Engineering Blog</source><guid isPermaLink="true">https://blog.ibtisam-iq.com/why-i-rewrote-my-jenkinsfile/</guid> <enclosure url="https://blog.ibtisam-iq.com/assets/images/social/why-i-rewrote-my-jenkinsfile.png" type="image/png" length="76803" /> </item> <item> <title>Zero Compute, and Still a Dozen Decisions</title> <author>Muhammad Ibtisam</author> <category>AWS</category> <category>AWS KMS</category> <category>Amazon S3</category> <category>Cloud Platforms</category> <category>CloudFront</category> <category>Cost Optimisation</category> <category>Security</category> <description>&lt;h1&gt;Zero Compute, and Still a Dozen Decisions&lt;/h1&gt; &lt;p&gt;Seven days of globally distributed static hosting on AWS cost me $1.45 across CloudFront, three S3 buckets, CloudTrail and KMS. There is no compute in it at all. No Lambda, no container, no instance.&lt;/p&gt; &lt;p&gt;&#34;Static site on S3&#34; gets treated as the trivial deployment, and the hosting genuinely is trivial. Everything around it is not, and the decisions turn out to be about who can read the bucket, which key encrypted the object, and what happens when a path does not exist.&lt;/p&gt;</description> <link>https://blog.ibtisam-iq.com/cloudfront-oac-dual-kms-static-hosting/</link> <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate> <source url="https://blog.ibtisam-iq.com/feed_rss_created.xml">Muhammad Ibtisam | Engineering Blog</source><guid isPermaLink="true">https://blog.ibtisam-iq.com/cloudfront-oac-dual-kms-static-hosting/</guid> <enclosure url="https://blog.ibtisam-iq.com/assets/images/social/cloudfront-oac-dual-kms-static-hosting.png" type="image/png" length="70472" /> </item> <item> <title>401 and 403 Are Different Failures, and One of Them Is Unrecoverable</title> <author>Muhammad Ibtisam</author> <category>AWS</category> <category>Amazon EKS</category> <category>Cloud Platforms</category> <category>Debugging</category> <category>IAM</category> <category>Kubernetes</category> <category>Security</category> <description>&lt;h1&gt;401 and 403 Are Different Failures, and One of Them Is Unrecoverable&lt;/h1&gt; &lt;p&gt;&lt;code&gt;kubectl&lt;/code&gt; returned 403 on a cluster I had just created. Later, on the same cluster, it returned 401. Those two numbers look like degrees of the same problem and they are not: one meant my identity was known and unauthorised, the other meant it was not known at all, and the second one could not be fixed without destroying the cluster.&lt;/p&gt; &lt;p&gt;The reason both were possible is a setting that can only be chosen once.&lt;/p&gt;</description> <link>https://blog.ibtisam-iq.com/eks-authentication-modes/</link> <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate> <source url="https://blog.ibtisam-iq.com/feed_rss_created.xml">Muhammad Ibtisam | Engineering Blog</source><guid isPermaLink="true">https://blog.ibtisam-iq.com/eks-authentication-modes/</guid> <enclosure url="https://blog.ibtisam-iq.com/assets/images/social/eks-authentication-modes.png" type="image/png" length="79219" /> </item> <item> <title>A Pod With AWS Permissions and No Credentials</title> <author>Muhammad Ibtisam</author> <category>AWS</category> <category>Amazon EKS</category> <category>Cloud Platforms</category> <category>IAM</category> <category>Kubernetes</category> <category>Security</category> <category>Serverless</category> <description>&lt;h1&gt;A Pod With AWS Permissions and No Credentials&lt;/h1&gt; &lt;p&gt;Two services in this cluster talk to AWS. Neither has an access key, a Secret, or anything in a values file that could leak one. They assume an IAM role through their service account, and the SDK inside them picks it up without being told.&lt;/p&gt; &lt;p&gt;That mechanism is IRSA, and the part worth writing down is not how to enable it. It is where the boundary sits: which object owns the binding, and why keeping it out of the Helm chart is what lets the same chart still run on a laptop.&lt;/p&gt;</description> <link>https://blog.ibtisam-iq.com/irsa-serverless-event-pipeline/</link> <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate> <source url="https://blog.ibtisam-iq.com/feed_rss_created.xml">Muhammad Ibtisam | Engineering Blog</source><guid isPermaLink="true">https://blog.ibtisam-iq.com/irsa-serverless-event-pipeline/</guid> <enclosure url="https://blog.ibtisam-iq.com/assets/images/social/irsa-serverless-event-pipeline.png" type="image/png" length="77489" /> </item> <item> <title>A Site That Loads Proves Almost Nothing</title> <author>Muhammad Ibtisam</author> <category>AWS</category> <category>AWS KMS</category> <category>Amazon S3</category> <category>Cloud Platforms</category> <category>CloudFront</category> <category>Debugging</category> <category>Verification</category> <description>&lt;h1&gt;A Site That Loads Proves Almost Nothing&lt;/h1&gt; &lt;p&gt;The home page rendering proves CloudFront serves content. It does not prove the bucket is private, that replication runs, that audit logs are recorded, that encryption is uniform, or that the cache is working. All five can be wrong on a site that looks perfect, and four of the five fail without producing an error.&lt;/p&gt; &lt;p&gt;This is the verification pass for that architecture, starting with the status code that means four different things.&lt;/p&gt;</description> <link>https://blog.ibtisam-iq.com/static-hosting-verification-and-teardown/</link> <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate> <source url="https://blog.ibtisam-iq.com/feed_rss_created.xml">Muhammad Ibtisam | Engineering Blog</source><guid isPermaLink="true">https://blog.ibtisam-iq.com/static-hosting-verification-and-teardown/</guid> <enclosure url="https://blog.ibtisam-iq.com/assets/images/social/static-hosting-verification-and-teardown.png" type="image/png" length="74662" /> </item> <item> <title>One Chart, a Ladder of Dependencies</title> <author>Muhammad Ibtisam</author> <category>Amazon EKS</category> <category>Architecture</category> <category>Containers &amp; Orchestration</category> <category>Helm</category> <category>Helmfile</category> <category>Kubernetes</category> <category>Microservices</category> <description>&lt;h1&gt;One Chart, a Ladder of Dependencies&lt;/h1&gt; &lt;p&gt;The same Helm chart deploys my orders service six different ways: in memory, on PostgreSQL with in-memory messaging, on PostgreSQL and RabbitMQ backed by local disk, the same pair on EBS, both pointed at external endpoints, or PostgreSQL with AWS SQS. Six values files, one chart, no forks.&lt;/p&gt; &lt;p&gt;I got there by being wrong about what portability means.&lt;/p&gt;</description> <link>https://blog.ibtisam-iq.com/helmfile-dependency-ladder/</link> <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate> <source url="https://blog.ibtisam-iq.com/feed_rss_created.xml">Muhammad Ibtisam | Engineering Blog</source><guid isPermaLink="true">https://blog.ibtisam-iq.com/helmfile-dependency-ladder/</guid> <enclosure url="https://blog.ibtisam-iq.com/assets/images/social/helmfile-dependency-ladder.png" type="image/png" length="65786" /> </item> <item> <title>Reading a Helm Chart You Did Not Write</title> <author>Muhammad Ibtisam</author> <category>Architecture</category> <category>Containers &amp; Orchestration</category> <category>Debugging</category> <category>Helm</category> <category>Kubernetes</category> <category>Microservices</category> <description>&lt;h1&gt;Reading a Helm Chart You Did Not Write&lt;/h1&gt; &lt;p&gt;I set &lt;code&gt;app.messaging.sqs.topic&lt;/code&gt; in a values file. Helm accepted it. The chart rendered without error. The deployed pod did not have the environment variable, because the chart contains no reference to SQS anywhere.&lt;/p&gt; &lt;p&gt;I found that by reading the template, not by debugging the application. That is the skill this post is about, because most Helm charts you deploy are charts someone else wrote.&lt;/p&gt;</description> <link>https://blog.ibtisam-iq.com/reading-a-helm-chart-you-did-not-write/</link> <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate> <source url="https://blog.ibtisam-iq.com/feed_rss_created.xml">Muhammad Ibtisam | Engineering Blog</source><guid isPermaLink="true">https://blog.ibtisam-iq.com/reading-a-helm-chart-you-did-not-write/</guid> <enclosure url="https://blog.ibtisam-iq.com/assets/images/social/reading-a-helm-chart-you-did-not-write.png" type="image/png" length="70358" /> </item> <item> <title>Four Add-ons Between a Bare EKS Cluster and a Working One</title> <author>Muhammad Ibtisam</author> <category>AWS</category> <category>Amazon EKS</category> <category>Containers &amp; Orchestration</category> <category>Gateway API</category> <category>Kubernetes</category> <category>Networking</category> <category>Storage</category> <description>&lt;h1&gt;Four Add-ons Between a Bare EKS Cluster and a Working One&lt;/h1&gt; &lt;p&gt;A freshly provisioned EKS cluster cannot provision a load balancer, cannot create a persistent volume on a modern disk type, cannot route Gateway API traffic, and cannot create a DNS record. It runs pods and that is roughly it.&lt;/p&gt; &lt;p&gt;Four add-ons close that gap, and three of them have a default that silently does the wrong thing.&lt;/p&gt;</description> <link>https://blog.ibtisam-iq.com/eks-cluster-addons/</link> <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate> <source url="https://blog.ibtisam-iq.com/feed_rss_created.xml">Muhammad Ibtisam | Engineering Blog</source><guid isPermaLink="true">https://blog.ibtisam-iq.com/eks-cluster-addons/</guid> <enclosure url="https://blog.ibtisam-iq.com/assets/images/social/eks-cluster-addons.png" type="image/png" length="87271" /> </item> <item> <title>The EKS Module Accepted the Setting and Never Sent It</title> <author>Muhammad Ibtisam</author> <category>AWS</category> <category>Amazon EKS</category> <category>Debugging</category> <category>IAM</category> <category>Infrastructure &amp; IaC</category> <category>Infrastructure as Code</category> <category>Terraform</category> <description>&lt;h1&gt;The EKS Module Accepted the Setting and Never Sent It&lt;/h1&gt; &lt;p&gt;Terraform applied cleanly. The cluster reached ACTIVE. Then &lt;code&gt;kubectl&lt;/code&gt; returned 401, and it turned out that nobody, including the account that created it, had permission to talk to the thing that had just been created successfully.&lt;/p&gt; &lt;p&gt;The setting that grants that permission was in my configuration. The module took it, validated it, and did not pass it to AWS.&lt;/p&gt;</description> <link>https://blog.ibtisam-iq.com/terraform-eks-module-silent-drop/</link> <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate> <source url="https://blog.ibtisam-iq.com/feed_rss_created.xml">Muhammad Ibtisam | Engineering Blog</source><guid isPermaLink="true">https://blog.ibtisam-iq.com/terraform-eks-module-silent-drop/</guid> <enclosure url="https://blog.ibtisam-iq.com/assets/images/social/terraform-eks-module-silent-drop.png" type="image/png" length="81650" /> </item> <item> <title>Seventeen Errors, and the Ones That Were Caused by the Fix</title> <author>Muhammad Ibtisam</author> <category>AWS</category> <category>Amazon EKS</category> <category>Debugging</category> <category>IAM</category> <category>Infrastructure &amp; IaC</category> <category>Infrastructure as Code</category> <category>Terraform</category> <description>&lt;h1&gt;Seventeen Errors, and the Ones That Were Caused by the Fix&lt;/h1&gt; &lt;p&gt;Provisioning EKS in a restricted AWS account produced seventeen distinct failures. What made it hard was not the count. It was that several of them only existed because of the fix for the previous one.&lt;/p&gt; &lt;p&gt;Three of the chains are worth walking through, because the pattern they share is the actual lesson: in a constrained environment, the correct move is often to back out rather than push forward.&lt;/p&gt;</description> <link>https://blog.ibtisam-iq.com/terraform-error-cascades/</link> <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate> <source url="https://blog.ibtisam-iq.com/feed_rss_created.xml">Muhammad Ibtisam | Engineering Blog</source><guid isPermaLink="true">https://blog.ibtisam-iq.com/terraform-error-cascades/</guid> <enclosure url="https://blog.ibtisam-iq.com/assets/images/social/terraform-error-cascades.png" type="image/png" length="84155" /> </item> <item> <title>The Ampersand That Silently Truncated My Database URL</title> <author>Muhammad Ibtisam</author> <category>Configuration</category> <category>Databases</category> <category>Debugging</category> <category>Linux &amp; System Administration</category> <category>Spring Boot</category> <category>Twelve-Factor</category> <description>&lt;h1&gt;The Ampersand That Silently Truncated My Database URL&lt;/h1&gt; &lt;p&gt;The connection string was correct. I checked it several times. The application still could not reach MySQL, and the error said nothing useful about why.&lt;/p&gt; &lt;p&gt;The URL was being cut in half before Java ever saw it, by the shell, at a character I had not thought of as a character.&lt;/p&gt;</description> <link>https://blog.ibtisam-iq.com/two-local-databases-one-artifact/</link> <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate> <source url="https://blog.ibtisam-iq.com/feed_rss_created.xml">Muhammad Ibtisam | Engineering Blog</source><guid isPermaLink="true">https://blog.ibtisam-iq.com/two-local-databases-one-artifact/</guid> <enclosure url="https://blog.ibtisam-iq.com/assets/images/social/two-local-databases-one-artifact.png" type="image/png" length="81709" /> </item> <item> <title>Two Failures Behind One Load Balancer, and Why Both Components Were Right</title> <author>Muhammad Ibtisam</author> <category>AWS</category> <category>Debugging</category> <category>Load Balancing</category> <category>Networking &amp; Storage</category> <category>Spring Boot</category> <category>TLS</category> <category>Troubleshooting</category> <description>&lt;h1&gt;Two Failures Behind One Load Balancer, and Why Both Components Were Right&lt;/h1&gt; &lt;p&gt;The Auto Scaling Group kept replacing instances. The application kept starting cleanly. Neither of those statements was wrong, and the gap between them took most of an afternoon to close. Then the moment the health check passed, a second failure appeared underneath it that had been invisible until the first one was gone.&lt;/p&gt;</description> <link>https://blog.ibtisam-iq.com/alb-health-check-https-redirect-loop/</link> <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate> <source url="https://blog.ibtisam-iq.com/feed_rss_created.xml">Muhammad Ibtisam | Engineering Blog</source><guid isPermaLink="true">https://blog.ibtisam-iq.com/alb-health-check-https-redirect-loop/</guid> <enclosure url="https://blog.ibtisam-iq.com/assets/images/social/alb-health-check-https-redirect-loop.png" type="image/png" length="82135" /> </item> <item> <title>An ACME Challenge That Could Not Reach Itself</title> <author>Muhammad Ibtisam</author> <category>Gateway API</category> <category>Kubernetes</category> <category>Lets Encrypt</category> <category>Networking &amp; Storage</category> <category>TLS</category> <category>Troubleshooting</category> <category>cert-manager</category> <description>&lt;h1&gt;An ACME Challenge That Could Not Reach Itself&lt;/h1&gt; &lt;p&gt;Let&#39;s Encrypt could not reach my cluster to validate a domain. That part I expected to fix. What took the rest of the day was that the cluster could not reach itself either, and cert-manager will not ask Let&#39;s Encrypt for anything until it can.&lt;/p&gt;</description> <link>https://blog.ibtisam-iq.com/cert-manager-gateway-http01-baremetal/</link> <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate> <source url="https://blog.ibtisam-iq.com/feed_rss_created.xml">Muhammad Ibtisam | Engineering Blog</source><guid isPermaLink="true">https://blog.ibtisam-iq.com/cert-manager-gateway-http01-baremetal/</guid> <enclosure url="https://blog.ibtisam-iq.com/assets/images/social/cert-manager-gateway-http01-baremetal.png" type="image/png" length="76267" /> </item> <item> <title>TLS Behind NAT Is Two Problems, Not One</title> <author>Muhammad Ibtisam</author> <category>Cloudflare</category> <category>Kubernetes</category> <category>Lets Encrypt</category> <category>NAT</category> <category>Networking &amp; Storage</category> <category>TLS</category> <category>cert-manager</category> <description>&lt;h1&gt;TLS Behind NAT Is Two Problems, Not One&lt;/h1&gt; &lt;p&gt;A Kubernetes cluster on a private address cannot use the HTTP-01 challenge. Not because something is misconfigured, but because the challenge requires Let&#39;s Encrypt to open a connection to you, and nothing routable exists to connect to.&lt;/p&gt; &lt;p&gt;The mistake I made next was assuming that solving the certificate solved the problem. It does not. Getting a trusted certificate and being reachable from the internet are separate problems with separate solutions, and one of the three approaches below fixes only the first.&lt;/p&gt;</description> <link>https://blog.ibtisam-iq.com/tls-three-approaches-behind-nat/</link> <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate> <source url="https://blog.ibtisam-iq.com/feed_rss_created.xml">Muhammad Ibtisam | Engineering Blog</source><guid isPermaLink="true">https://blog.ibtisam-iq.com/tls-three-approaches-behind-nat/</guid> <enclosure url="https://blog.ibtisam-iq.com/assets/images/social/tls-three-approaches-behind-nat.png" type="image/png" length="74749" /> </item> <item> <title>Two cert-manager Solvers, and the Flag That Is Off By Default</title> <author>Muhammad Ibtisam</author> <category>Gateway API</category> <category>Ingress</category> <category>Kubernetes</category> <category>Networking &amp; Storage</category> <category>TLS</category> <category>Troubleshooting</category> <category>cert-manager</category> <description>&lt;h1&gt;Two cert-manager Solvers, and the Flag That Is Off By Default&lt;/h1&gt; &lt;p&gt;cert-manager has two HTTP-01 solvers. Which one you need is not a preference, it is determined entirely by what is routing traffic in your cluster. Pick the wrong one and the challenge never gets served.&lt;/p&gt; &lt;p&gt;Pick the right one and it still may not work, because on a manifest install the Gateway API solver is compiled in and switched off.&lt;/p&gt;</description> <link>https://blog.ibtisam-iq.com/cert-manager-ingress-vs-gateway-solver/</link> <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate> <source url="https://blog.ibtisam-iq.com/feed_rss_created.xml">Muhammad Ibtisam | Engineering Blog</source><guid isPermaLink="true">https://blog.ibtisam-iq.com/cert-manager-ingress-vs-gateway-solver/</guid> <enclosure url="https://blog.ibtisam-iq.com/assets/images/social/cert-manager-ingress-vs-gateway-solver.png" type="image/png" length="88615" /> </item> <item> <title>Gateway API Three Ways, and What It Actually Buys Over Ingress</title> <author>Muhammad Ibtisam</author> <category>Amazon EKS</category> <category>Architecture</category> <category>Gateway API</category> <category>Ingress</category> <category>Kubernetes</category> <category>Networking</category> <category>Networking &amp; Storage</category> <description>&lt;h1&gt;Gateway API Three Ways, and What It Actually Buys Over Ingress&lt;/h1&gt; &lt;p&gt;I ran the same routing problem three times: NGINX Gateway Fabric on a bare metal cluster, the AWS Load Balancer Controller on EKS, and an ALB Ingress Group sharing one load balancer across three services. Two used Gateway API and one used Ingress, and the differences between them were not the ones I expected.&lt;/p&gt;</description> <link>https://blog.ibtisam-iq.com/gateway-api-three-ways/</link> <pubDate>Sun, 02 Aug 2026 00:00:00 +0000</pubDate> <source url="https://blog.ibtisam-iq.com/feed_rss_created.xml">Muhammad Ibtisam | Engineering Blog</source><guid isPermaLink="true">https://blog.ibtisam-iq.com/gateway-api-three-ways/</guid> <enclosure url="https://blog.ibtisam-iq.com/assets/images/social/gateway-api-three-ways.png" type="image/png" length="84080" /> </item> </channel> </rss>