<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: zakaria zermani</title>
    <description>The latest articles on DEV Community by zakaria zermani (@zaki_zermani_57ff49f53acf).</description>
    <link>https://dev.to/zaki_zermani_57ff49f53acf</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3117149%2F7c2368c0-a159-45d7-8994-535540d9d4fb.webp</url>
      <title>DEV Community: zakaria zermani</title>
      <link>https://dev.to/zaki_zermani_57ff49f53acf</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zaki_zermani_57ff49f53acf"/>
    <language>en</language>
    <item>
      <title>Stop Committing Secrets: A Practical Betterleaks + Git Hooks Setup for Every Development Team</title>
      <dc:creator>zakaria zermani</dc:creator>
      <pubDate>Thu, 15 Oct 2026 07:38:04 +0000</pubDate>
      <link>https://dev.to/zaki_zermani_57ff49f53acf/stop-committing-secrets-a-practical-betterleaks-git-hooks-setup-for-every-development-team-45ch</link>
      <guid>https://dev.to/zaki_zermani_57ff49f53acf/stop-committing-secrets-a-practical-betterleaks-git-hooks-setup-for-every-development-team-45ch</guid>
      <description>&lt;p&gt;Security incidents often start with a simple mistake.&lt;/p&gt;

&lt;p&gt;A developer accidentally commits an API key, a database password, a private key, or a cloud credential. The secret gets pushed to a repository, appears in CI logs, gets replicated to forks, or becomes part of Git history.&lt;/p&gt;

&lt;p&gt;Even when detected quickly, the cleanup can be painful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rotate credentials&lt;/li&gt;
&lt;li&gt;Clean repository history&lt;/li&gt;
&lt;li&gt;Investigate exposure&lt;/li&gt;
&lt;li&gt;Update environments&lt;/li&gt;
&lt;li&gt;Document the incident&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A much better approach is to prevent secrets from being committed in the first place.&lt;/p&gt;

&lt;p&gt;In this article, we'll configure &lt;strong&gt;Betterleaks&lt;/strong&gt; and &lt;strong&gt;Git pre-commit hooks&lt;/strong&gt; to automatically scan staged changes and block commits containing sensitive information.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Local Secret Scanning Matters
&lt;/h2&gt;

&lt;p&gt;Many organizations rely on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub Secret Scanning&lt;/li&gt;
&lt;li&gt;GitLab Secret Detection&lt;/li&gt;
&lt;li&gt;CI/CD security pipelines&lt;/li&gt;
&lt;li&gt;Repository scanning solutions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While these tools are important, they usually identify problems after the secret has already entered the repository.&lt;/p&gt;

&lt;p&gt;Local scanning shifts detection further left.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits
&lt;/h3&gt;

&lt;p&gt;✅ Immediate feedback for developers&lt;/p&gt;

&lt;p&gt;✅ Secrets never reach Git history&lt;/p&gt;

&lt;p&gt;✅ Faster remediation&lt;/p&gt;

&lt;p&gt;✅ Consistent security practices&lt;/p&gt;

&lt;p&gt;✅ Reduced risk of accidental exposure&lt;/p&gt;

&lt;p&gt;The earlier a problem is discovered, the cheaper it is to fix.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Install Betterleaks
&lt;/h2&gt;

&lt;p&gt;Install Betterleaks on your workstation.&lt;/p&gt;

&lt;h3&gt;
  
  
  macOS
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;betterleaks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Linux
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;BETTERLEAKS_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1.8.1"&lt;/span&gt;

curl &lt;span class="nt"&gt;-sSfL&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"https://github.com/betterleaks/betterleaks/releases/download/v&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BETTERLEAKS_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/betterleaks_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BETTERLEAKS_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_linux_x64.tar.gz"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
| &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xz&lt;/span&gt;

&lt;span class="nb"&gt;sudo mv &lt;/span&gt;betterleaks /usr/local/bin/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verify Installation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;betterleaks &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a version number is displayed, you're ready to continue.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Store Git Hooks Inside the Repository
&lt;/h2&gt;

&lt;p&gt;By default, Git stores hooks inside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.git/hooks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem is that this directory is not version-controlled.&lt;/p&gt;

&lt;p&gt;To ensure every developer uses the same hooks, create a dedicated directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-project/
├── .githooks/
│   └── pre-commit
├── .betterleaks.toml
└── README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure Git to use this directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config core.hooksPath .githooks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command only needs to be executed once per cloned repository.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Create the Pre-Commit Hook
&lt;/h2&gt;

&lt;p&gt;Create the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.githooks/pre-commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="c"&gt;# Verify Betterleaks is installed&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; betterleaks &amp;amp;&amp;gt; /dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Betterleaks is not installed."&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Please install Betterleaks before committing."&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Running Betterleaks scan..."&lt;/span&gt;

betterleaks git &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--staged&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--config&lt;/span&gt; .betterleaks.toml

&lt;span class="nv"&gt;EXIT_CODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$EXIT_CODE&lt;/span&gt; &lt;span class="nt"&gt;-ne&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Secrets detected."&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Commit blocked."&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"No secrets found."&lt;/span&gt;
&lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make the hook executable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x .githooks/pre-commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now every commit will automatically trigger a secret scan.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Configure Betterleaks
&lt;/h2&gt;

&lt;p&gt;Create the configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.betterleaks.toml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Project-Wide Betterleaks Configuration"&lt;/span&gt;

&lt;span class="nn"&gt;[extend]&lt;/span&gt;
&lt;span class="py"&gt;useDefault&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="c"&gt;# Optional:&lt;/span&gt;
&lt;span class="c"&gt;# disabledRules = ["generic-api-key"]&lt;/span&gt;

&lt;span class="nn"&gt;[[rules]]&lt;/span&gt;
&lt;span class="py"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"custom-api-token"&lt;/span&gt;

&lt;span class="py"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Detect custom API tokens"&lt;/span&gt;

&lt;span class="py"&gt;regex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'''MYTOKEN_[A-Za-z0-9]{32}'''&lt;/span&gt;

&lt;span class="py"&gt;keywords&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="s"&gt;"MYTOKEN_"&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nn"&gt;[allowlist]&lt;/span&gt;

&lt;span class="py"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Ignore test fixtures"&lt;/span&gt;

&lt;span class="py"&gt;paths&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="s"&gt;'''(^|/)testdata/'''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;'''(^|/)fixtures/'''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;'''(^|/)__mocks__/'''&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="py"&gt;stopwords&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="s"&gt;"dummy_token"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"example_secret"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s"&gt;"test_api_key"&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses Betterleaks' built-in detection rules&lt;/li&gt;
&lt;li&gt;Adds project-specific secret detection&lt;/li&gt;
&lt;li&gt;Reduces false positives&lt;/li&gt;
&lt;li&gt;Excludes known test data&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 5: Test the Setup
&lt;/h2&gt;

&lt;p&gt;Let's verify that the hook works.&lt;/p&gt;

&lt;p&gt;Create a file containing a fake GitHub token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"token: ghp_AbC123xYz456D7Ef89GhI01JkLmNoPqRsTuV"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; test-secret.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stage the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add test-secret.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Attempt a commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"testing secret detection"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Running Betterleaks scan...

Secrets detected.
Commit blocked.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The commit will fail, preventing the secret from entering the repository.&lt;/p&gt;




&lt;h2&gt;
  
  
  Handling False Positives
&lt;/h2&gt;

&lt;p&gt;No detection tool is perfect.&lt;/p&gt;

&lt;p&gt;If Betterleaks incorrectly identifies a value as a secret, you have several options.&lt;/p&gt;

&lt;h3&gt;
  
  
  Allow a Specific Line
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;example_value # betterleaks:allow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Ignore Files or Directories
&lt;/h3&gt;

&lt;p&gt;Create a:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.betterleaksignore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;file to define exclusions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Customize Detection Rules
&lt;/h3&gt;

&lt;p&gt;Adjust your rules inside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.betterleaks.toml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal is to reduce noise while maintaining effective security controls.&lt;/p&gt;




&lt;h2&gt;
  
  
  Emergency Bypass
&lt;/h2&gt;

&lt;p&gt;In rare situations, you may need to bypass the hook:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;--no-verify&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"emergency commit"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use this carefully.&lt;/p&gt;

&lt;p&gt;If developers regularly bypass security controls, it may indicate that the rules need refinement.&lt;/p&gt;




&lt;h2&gt;
  
  
  Onboarding New Developers
&lt;/h2&gt;

&lt;p&gt;A simple developer onboarding process might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &amp;lt;repository&amp;gt;

&lt;span class="nb"&gt;cd&lt;/span&gt; &amp;lt;repository&amp;gt;

brew &lt;span class="nb"&gt;install &lt;/span&gt;betterleaks

git config core.hooksPath .githooks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it.&lt;/p&gt;

&lt;p&gt;From that point onward, every commit is automatically checked before it is created.&lt;/p&gt;




&lt;h2&gt;
  
  
  Defense in Depth: Local + CI/CD Scanning
&lt;/h2&gt;

&lt;p&gt;Local secret scanning should complement, not replace, existing security controls.&lt;/p&gt;

&lt;p&gt;A layered approach typically includes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pre-Commit Hooks&lt;/td&gt;
&lt;td&gt;Immediate developer feedback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pull Request Validation&lt;/td&gt;
&lt;td&gt;Team-level review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI/CD Scanning&lt;/td&gt;
&lt;td&gt;Automated enforcement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repository Scanning&lt;/td&gt;
&lt;td&gt;Continuous monitoring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secret Management Solutions&lt;/td&gt;
&lt;td&gt;Secure storage and rotation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Security controls are most effective when they work together.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Secret leaks are among the easiest security incidents to prevent.&lt;/p&gt;

&lt;p&gt;By integrating Betterleaks directly into the local development workflow, teams can catch sensitive information before it enters a repository.&lt;/p&gt;

&lt;p&gt;The setup is lightweight, easy to maintain, and provides immediate value without disrupting developers.&lt;/p&gt;

&lt;p&gt;If you're already scanning repositories and CI/CD pipelines for secrets, consider adding local detection as another layer of defense.&lt;/p&gt;

&lt;p&gt;The best secret leak is the one that never reaches Git in the first place.&lt;/p&gt;




&lt;h2&gt;
  
  
  Have You Tried Local Secret Scanning?
&lt;/h2&gt;

&lt;p&gt;How does your team prevent accidental secret exposure?&lt;/p&gt;

&lt;p&gt;Do you rely on GitHub Secret Scanning, GitLab Secret Detection, gitleaks, Betterleaks, custom tooling, or a combination of approaches?&lt;/p&gt;

&lt;p&gt;I'd be interested to hear what has worked best in your environment.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>security</category>
      <category>git</category>
    </item>
    <item>
      <title>From Ingress API to Gateway API: Why the Migration Is Worth It</title>
      <dc:creator>zakaria zermani</dc:creator>
      <pubDate>Sun, 26 Jul 2026 17:29:55 +0000</pubDate>
      <link>https://dev.to/zaki_zermani_57ff49f53acf/von-ingress-api-zu-gateway-api-warum-sich-der-wechsel-lohnt-5am6</link>
      <guid>https://dev.to/zaki_zermani_57ff49f53acf/von-ingress-api-zu-gateway-api-warum-sich-der-wechsel-lohnt-5am6</guid>
      <description>&lt;p&gt;Kubernetes users have relied on the Ingress API for years as the standard way to route HTTP(S) traffic into a cluster. However, the Ingress API is starting to show its limitations—and that's exactly why the &lt;strong&gt;Gateway API&lt;/strong&gt; has emerged as a more modern and flexible successor.&lt;/p&gt;

&lt;p&gt;In this article, we'll explore why migrating makes sense, what changes conceptually, and how common Ingress features map to the Gateway API.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5qw0c9g624oata003h4e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5qw0c9g624oata003h4e.png" alt="Migration von Ingress API zu Gateway API" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Migrate at All?
&lt;/h2&gt;

&lt;p&gt;The Ingress API has three fundamental weaknesses that become apparent very quickly in real-world environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Limited Functionality
&lt;/h3&gt;

&lt;p&gt;The Ingress API supports only TLS termination and basic content-based routing for HTTP traffic. Need TCP, UDP, or gRPC routing? You're out of luck.&lt;/p&gt;

&lt;p&gt;To provide more advanced functionality, Ingress controllers rely heavily on &lt;strong&gt;annotations&lt;/strong&gt;—proprietary extensions that exist outside the actual Kubernetes standard.&lt;/p&gt;

&lt;p&gt;The problem is that each implementation (NGINX, Traefik, Envoy, and others) ships with its own set of annotations, which are not necessarily compatible with one another. If you want to switch Ingress controllers, you typically need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Identify all annotations currently in use.&lt;/li&gt;
&lt;li&gt;Find equivalent functionality in the new controller.&lt;/li&gt;
&lt;li&gt;Rebuild the configuration manually.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This makes migrating between implementations difficult—and sometimes nearly impossible.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. No Real Authorization Model
&lt;/h3&gt;

&lt;p&gt;The classic Ingress model revolves around a single central resource. As a result, there is effectively only one primary role: the person creating the Ingress resource.&lt;/p&gt;

&lt;p&gt;That role can simultaneously define routing rules, configure TLS, and in some cases even influence the underlying load-balancing infrastructure.&lt;/p&gt;

&lt;p&gt;In small clusters operated by a single team, this isn't usually a problem. But consider the following scenario:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Team A operates an online shop&lt;/li&gt;
&lt;li&gt;Team B operates an API&lt;/li&gt;
&lt;li&gt;Team C operates a customer portal&lt;/li&gt;
&lt;li&gt;All teams share the same load balancer or Ingress controller&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Ingress model provides no clean separation between infrastructure operators, application administrators, and developers. As a result, developers can potentially create configurations that affect shared infrastructure without any standardized role model governing those permissions.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. An Unwieldy API Design
&lt;/h3&gt;

&lt;p&gt;Annotations are simple key-value strings stored in the metadata section rather than as structured fields within the relevant part of the specification.&lt;/p&gt;

&lt;p&gt;As the number of annotations grows, an Ingress resource quickly becomes difficult to read, maintain, and understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Differences
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Personas
&lt;/h3&gt;

&lt;p&gt;One of the biggest conceptual improvements introduced by the Gateway API is its clearly defined role model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ingress API Personas
&lt;/h3&gt;

&lt;p&gt;With the Ingress API, there is essentially only one explicit persona:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User&lt;/strong&gt;: Owner of the Ingress resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, there are two implicit personas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure Provider&lt;/strong&gt;: Manages a provider-managed Ingress controller&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cluster Operator/Admin&lt;/strong&gt;: Manages self-hosted Ingress controllers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These personas only became formally recognized with the later introduction of the &lt;code&gt;IngressClass&lt;/code&gt; resource.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gateway API Personas
&lt;/h3&gt;

&lt;p&gt;The Gateway API introduces a clear separation of responsibilities from the start:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application Developer&lt;/strong&gt;: Defines routing rules for applications&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application Admin&lt;/strong&gt;: Defines entry points for external client traffic, including TLS termination&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cluster Operator&lt;/strong&gt;: Defines gateway entry points and TLS configuration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure Provider&lt;/strong&gt;: Provides the GatewayClass and controller implementation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This model aligns much better with organizations where multiple teams share the same load-balancing infrastructure.&lt;/p&gt;

&lt;p&gt;Importantly, adopting the Gateway API does &lt;strong&gt;not&lt;/strong&gt; require abandoning self-service workflows. It remains perfectly possible to define a single RBAC role that combines the responsibilities of Developer, Admin, and Operator.&lt;/p&gt;

&lt;h2&gt;
  
  
  Functionality and Extensibility
&lt;/h2&gt;

&lt;p&gt;The Gateway API covers all features available in Ingress—and adds many capabilities that previously required annotations. As a result, configurations become significantly more portable across implementations.&lt;/p&gt;

&lt;p&gt;For features that cannot realistically be standardized—such as authentication, connection timeouts, or health checks—the Gateway API provides three official extension mechanisms.&lt;/p&gt;

&lt;h3&gt;
  
  
  External References
&lt;/h3&gt;

&lt;p&gt;A Gateway API resource can reference an implementation-specific custom resource. This keeps the standard API lean while still allowing vendors such as Envoy Gateway or Istio to provide advanced features.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTPRoute
   |
   +--&amp;gt; Standard Gateway API fields
   |
   +--&amp;gt; Vendor-specific extension fields (Custom Resource)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, an &lt;code&gt;HTTPRouteFilter&lt;/code&gt; can use an &lt;code&gt;extensionRef&lt;/code&gt; to reference a vendor-specific JWT authentication resource that is not part of the standard:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;filters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ExtensionRef&lt;/span&gt;
  &lt;span class="na"&gt;extensionRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gateway.envoyproxy.io&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;JwtAuthentication&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;company-auth&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Custom Implementations
&lt;/h3&gt;

&lt;p&gt;Some features are intentionally left implementation-specific.&lt;/p&gt;

&lt;p&gt;A good example is the &lt;code&gt;RegularExpression&lt;/code&gt; type of &lt;code&gt;HTTPPathMatch&lt;/code&gt;, where behavior depends on the controller implementation. These capabilities fall under the "implementation-specific" or "custom" conformance level.&lt;/p&gt;

&lt;h3&gt;
  
  
  Policies
&lt;/h3&gt;

&lt;p&gt;For data-plane functionality such as authentication, authorization, rate limiting, WAF rules, or caching, vendors can define their own policy resources.&lt;/p&gt;

&lt;p&gt;The Gateway API does not dictate how those resources should be designed, but it does standardize &lt;strong&gt;how policies are attached to Gateway API resources&lt;/strong&gt;. This creates a more consistent user experience across vendors.&lt;/p&gt;

&lt;p&gt;The key difference compared to External References is that &lt;strong&gt;the policy references the route&lt;/strong&gt;, not the other way around.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HTTPRoute&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the Gateway API approach looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HTTPRoute&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;webshop&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AuthenticationPolicy&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;targetRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HTTPRoute&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;webshop&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notably, annotations are &lt;strong&gt;not&lt;/strong&gt; considered an official extension mechanism in the Gateway API and are strongly discouraged for implementations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature Mapping: Ingress to Gateway API
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Ingress Concept&lt;/th&gt;
&lt;th&gt;Gateway API Equivalent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Entry Points&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Must be explicitly defined as listeners in a &lt;code&gt;Gateway&lt;/code&gt; resource&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TLS Termination&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Defined on the Gateway listener; certificates still reside in Secrets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Routing Rules&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Path matching maps directly to an &lt;code&gt;HTTPRoute&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Default Backend&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No direct equivalent; must be defined explicitly as a routing rule using a &lt;code&gt;/&lt;/code&gt; prefix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;IngressClass&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;parentRef&lt;/code&gt; in the &lt;code&gt;HTTPRoute&lt;/code&gt; points to the corresponding &lt;code&gt;Gateway&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Routing in Detail: Host-Specific vs. Global
&lt;/h3&gt;

&lt;p&gt;A noteworthy difference is how routing rules are associated with hostnames.&lt;/p&gt;

&lt;p&gt;With Ingress, &lt;strong&gt;each hostname has its own rule block&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;shop.example.com&lt;/span&gt;
    &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
        &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;shop-service&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api.example.com&lt;/span&gt;
    &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
        &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api-service&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;HTTPRoute&lt;/code&gt;, routing rules automatically apply to &lt;strong&gt;all specified hostnames&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hostnames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;shop.example.com&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;api.example.com&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;matches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
    &lt;span class="na"&gt;backendRefs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Merging and Conflict Resolution
&lt;/h3&gt;

&lt;p&gt;Ingress never standardized how configurations should be merged or how routing conflicts should be resolved. Each controller handles these situations differently.&lt;/p&gt;

&lt;p&gt;The Gateway API, in contrast, explicitly defines rule-merging and conflict-resolution behavior, ensuring consistent behavior across conformant implementations.&lt;/p&gt;

&lt;h2&gt;
  
  
  What About Annotations?
&lt;/h2&gt;

&lt;p&gt;Because annotations are inherently implementation-specific, their migration depends on both the old Ingress controller and the new Gateway implementation.&lt;/p&gt;

&lt;p&gt;Let's take NGINX as an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;nginx.ingress.kubernetes.io/rewrite-target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
    &lt;span class="na"&gt;nginx.ingress.kubernetes.io/ssl-redirect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These annotations are understood only by the NGINX Ingress Controller. Other controllers either ignore them or provide their own alternatives.&lt;/p&gt;

&lt;p&gt;The good news is that many previously annotation-based features are now part of the official standard.&lt;/p&gt;

&lt;p&gt;For example, this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;nginx.ingress.kubernetes.io/ssl-redirect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;becomes a standard Gateway API filter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;filters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RequestRedirect&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For features that remain implementation-specific—such as JWT authentication, WAF rules, or advanced Envoy capabilities—you'll need to consult the documentation of the respective Gateway implementation to identify the appropriate extension mechanism.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementations and Conformance
&lt;/h2&gt;

&lt;p&gt;The Gateway API defines two implementation profiles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gateway&lt;/strong&gt;: Designed for north-south traffic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mesh&lt;/strong&gt;: Designed for east-west traffic within a cluster or across cluster sets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each profile has its own conformance tests.&lt;/p&gt;

&lt;p&gt;There are currently three conformance levels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Conformant&lt;/strong&gt;: e.g., Traefik (Controller), Cilium (Controller &amp;amp; Mesh)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Partially Conformant&lt;/strong&gt;: e.g., Envoy Gateway (used, among others, by Giant Swarm)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stale&lt;/strong&gt;: e.g., Azure Application Gateway for Containers (Controller)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Automated Migration
&lt;/h2&gt;

&lt;p&gt;Fortunately, migrating doesn't have to start from scratch.&lt;/p&gt;

&lt;p&gt;The Kubernetes SIGs project &lt;strong&gt;ingress2gateway&lt;/strong&gt; automatically converts existing Ingress resources into Gateway API resources and can significantly reduce the amount of manual work involved:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/kubernetes-sigs/ingress2gateway" rel="noopener noreferrer"&gt;https://github.com/kubernetes-sigs/ingress2gateway&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The Gateway API addresses the three biggest shortcomings of the Ingress API at once: richer built-in functionality, a clear role model for multi-team Kubernetes environments, and a structured API design that replaces annotation sprawl with well-defined resources and extension mechanisms.&lt;/p&gt;

&lt;p&gt;If you're currently struggling with large numbers of implementation-specific annotations or coordinating multiple teams on shared Ingress infrastructure, it's well worth taking a serious look at migrating to the Gateway API—ideally with &lt;strong&gt;ingress2gateway&lt;/strong&gt; as a starting point for the transition.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>infrastructure</category>
      <category>kubernetes</category>
      <category>networking</category>
    </item>
    <item>
      <title>Entwicklung auf SAP BTP: Struktur, Tools &amp; Deployment im Überblick</title>
      <dc:creator>zakaria zermani</dc:creator>
      <pubDate>Sun, 04 May 2025 20:24:27 +0000</pubDate>
      <link>https://dev.to/zaki_zermani_57ff49f53acf/entwicklung-auf-sap-btp-struktur-tools-deployment-im-uberblick-23l9</link>
      <guid>https://dev.to/zaki_zermani_57ff49f53acf/entwicklung-auf-sap-btp-struktur-tools-deployment-im-uberblick-23l9</guid>
      <description>&lt;h2&gt;Einführung in SAP BTP&lt;/h2&gt;

&lt;h3&gt;Was ist SAP Business Technology Platform?&lt;/h3&gt;

&lt;p&gt;Die SAP Business Technology Platform (SAP BTP) ist eine integrierte Plattform-as-a-Service (PaaS), die es Unternehmen ermöglicht, Anwendungen und Erweiterungen effizient zu entwickeln, zu integrieren und bereitzustellen. SAP BTP kombiniert Datenbankdienste, Analytik, Integrationsfunktionen sowie Anwendungsentwicklungstools in einer zentralen Umgebung. Sie unterstützt verschiedene Laufzeitumgebungen, darunter Cloud Foundry, Kyma und ABAP.&lt;/p&gt;

&lt;h3&gt;Warum auf SAP BTP entwickeln?&lt;/h3&gt;

&lt;p&gt;Die Entwicklung auf SAP BTP bietet zahlreiche Vorteile: Entwickler:innen können Anwendungen schnell in der Cloud erstellen, bestehende SAP-Lösungen erweitern und gleichzeitig moderne Technologien wie Machine Learning oder Event-driven Architecture nutzen. Durch die nahtlose Integration mit SAP S/4HANA, SAP SuccessFactors und anderen Systemen wird die BTP zur idealen Plattform für unternehmensweite Innovationen.&lt;/p&gt;



&lt;h2&gt;Die SAP BTP Account-Struktur verstehen&lt;/h2&gt;

&lt;h3&gt;Global Account, Subaccount &amp;amp; Directories&lt;/h3&gt;

&lt;p&gt;Die Account-Struktur von SAP BTP ist hierarchisch aufgebaut. An oberster Stelle steht der &lt;strong&gt;Global Account&lt;/strong&gt;, dem &lt;strong&gt;Subaccounts&lt;/strong&gt; untergeordnet sind. Innerhalb des global accounts oder der Subaccounts können sogenannte &lt;strong&gt;Directories&lt;/strong&gt; erstellt werden, um eine strukturierte Organisation zu ermöglichen – etwa nach Teams, Projekten oder Regionen.&lt;/p&gt;

&lt;h3&gt;Cloud Foundry Subaccount: Aufbau und Organisation&lt;/h3&gt;

&lt;p&gt;Ein Subaccount in der Cloud Foundry (CF) Umgebung entspricht einer eigenen Entwicklungs- und Laufzeitumgebung. Innerhalb eines CF-Subaccounts wird automatisch eine &lt;strong&gt;Organisation (Org)&lt;/strong&gt; erstellt, zu der mehrere &lt;strong&gt;Spaces&lt;/strong&gt; gehören können. Diese Spaces ermöglichen die Aufteilung von Ressourcen, Rollen und Deployments, z. B. für Entwicklung, Test und Produktion.&lt;/p&gt;

&lt;h3&gt;Orgs und Spaces: Hierarchie und Struktur&lt;/h3&gt;

&lt;p&gt;In der CF-Umgebung gilt eine 1:1-Beziehung zwischen Subaccount und Org. Eine Org kann jedoch beliebig viele Spaces beinhalten. Diese Trennung erlaubt eine granulare Zuweisung von Ressourcen (z. B. Quota, Memory) und fördert die Kollaboration in Projektteams. Spaces sind also essenziell für eine strukturierte und skalierbare Entwicklungslandschaft auf BTP.&lt;/p&gt;



&lt;h2&gt;Beispielhafte Struktur: Eine Skizze zur Visualisierung&lt;/h2&gt;

&lt;h3&gt;Visuelle Darstellung der Account-Hierarchie&lt;/h3&gt;

&lt;p&gt;Zur besseren Verständlichkeit bietet sich eine grafische Skizze an, die die Hierarchie von Global Account → Subaccount → Directory → Org → Space darstellt. Diese Struktur bildet das Fundament für die technische Umsetzung von Berechtigungen, Ressourcenmanagement und Anwendungsbereitstellung auf SAP BTP.&lt;/p&gt;  

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3fllhu1lvt3ziku0tijy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3fllhu1lvt3ziku0tijy.png" alt="Image description" width="565" height="438"&gt;&lt;/a&gt;&lt;br&gt;
Quelle: &lt;a href="https://developers.sap.com/tutorials/cp-trial-quick-onboarding.html" rel="noopener noreferrer"&gt;https://developers.sap.com/tutorials/cp-trial-quick-onboarding.html&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Empfohlene Aufteilung nach Use Case&lt;/h3&gt;

&lt;p&gt;Ein bewährtes Modell ist die Aufteilung der Subaccounts nach &lt;em&gt;Region&lt;/em&gt; oder &lt;em&gt;Business Unit&lt;/em&gt;, kombiniert mit einer projektbezogenen Nutzung der Directories und Spaces. So lassen sich verschiedene Anwendungsfälle – von ABAP-Entwicklung bis zu UI5-Webapps – klar trennen und effizient verwalten.&lt;/p&gt;



&lt;h2&gt;Entitlements vs. Quotas&lt;/h2&gt;

&lt;h3&gt;Was sind Entitlements?&lt;/h3&gt;

&lt;p&gt;In SAP BTP bezeichnen &lt;strong&gt;Entitlements&lt;/strong&gt; die Zuweisung von Diensten und Ressourcen an Subaccounts. Sie legen fest, welche Services überhaupt genutzt werden dürfen – zum Beispiel SAP HANA Cloud, Business Application Studio oder die ABAP Environment. Diese Berechtigungen werden auf der Ebene des Global Accounts verwaltet.&lt;/p&gt;

&lt;h3&gt;Quota Management im globalen Account&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Quotas&lt;/strong&gt; bestimmen, in welchem Umfang ein Dienst innerhalb eines Subaccounts verwendet werden darf. Während ein Entitlement lediglich die grundsätzliche Nutzung erlaubt, limitiert die Quota die konkrete Ressourcennutzung (z. B. Anzahl der Serviceinstanzen oder Speichermenge). Ein gutes Quota-Management ist entscheidend, um Performance und Kosten im Griff zu behalten.&lt;/p&gt;

&lt;h3&gt;Regionale Bindung eines Subaccounts&lt;/h3&gt;

&lt;p&gt;Jeder Subaccount ist genau &lt;strong&gt;einer Region&lt;/strong&gt; zugeordnet. Diese Region beeinflusst unter anderem die Verfügbarkeit von Diensten, Latenzzeiten und die rechtliche Rahmenbedingungen bezüglich Datenhaltung. Daher ist es sinnvoll, Subaccounts strategisch nach geografischer Nähe zu Nutzern oder regulatorischen Anforderungen auszuwählen.&lt;/p&gt;



&lt;h2&gt;Tools für Entwickler:innen auf SAP BTP&lt;/h2&gt;

&lt;h3&gt;Was ist die BTP CLI?&lt;/h3&gt;

&lt;p&gt;Die &lt;strong&gt;BTP Command Line Interface (BTP CLI)&lt;/strong&gt; ist ein zentrales Tool zur Verwaltung von globalen Accounts, Subaccounts, Directories und Diensten. Im Gegensatz zur CF CLI, die ausschließlich für die Cloud Foundry Umgebung zuständig ist, adressiert die BTP CLI die gesamte Plattformstruktur und erlaubt unter anderem die Aktivierung von Diensten, Zuweisung von Entitlements und das Konfigurieren von Directories.&lt;/p&gt;

&lt;h3&gt;Unterschiede zur CF CLI&lt;/h3&gt;

&lt;p&gt;Die &lt;strong&gt;CF CLI&lt;/strong&gt; ist spezialisiert auf die Interaktion mit der Cloud Foundry Umgebung – also auf das Deployment, die Verwaltung von Apps, Services, Orgs und Spaces. Die BTP CLI hingegen deckt übergeordnete Plattformebenen ab, wie die Einrichtung von Subaccounts, Service-Plänen und globalen Rollen. Für ein vollständiges Management der BTP-Struktur ist die Nutzung beider CLIs oft notwendig.&lt;/p&gt;

&lt;h3&gt;BTP CLI: Kontextbasiertes Arbeiten (global, subaccount, directory)&lt;/h3&gt;

&lt;p&gt;Ein zentraler Aspekt der BTP CLI ist das Arbeiten im &lt;strong&gt;kontextbasierten Modus&lt;/strong&gt;. Dabei kann ein spezifischer Kontext (z. B. ein bestimmter Subaccount oder ein Directory) als Ziel gesetzt werden. Wenn Sie also den Kontext, in dem Befehle ausgeführt werden, auf ein Directory oder ein Subaccount ändern wollen, können Sie dies mit dem Befehl **btp target** tun.&lt;/p&gt;



&lt;h2&gt;Arbeiten mit dem SAP Business Application Studio&lt;/h2&gt;

&lt;h3&gt;Dev Spaces erstellen und nutzen&lt;/h3&gt;

&lt;p&gt;Das &lt;strong&gt;SAP Business Application Studio (BAS)&lt;/strong&gt; ist eine moderne, webbasierte Entwicklungsumgebung auf der SAP BTP. Entwickler:innen können darin sogenannte &lt;strong&gt;Dev Spaces&lt;/strong&gt; erstellen – vorinstallierte, isolierte Entwicklungsumgebungen, die sofort einsatzbereit sind. Je nach gewähltem Szenario (z. B. SAP Fiori, CAP, ABAP) sind die entsprechenden Tools, Extensions und Laufzeitumgebungen bereits integriert.&lt;/p&gt;

&lt;h3&gt;Voraussetzungen und Subscription&lt;/h3&gt;

&lt;p&gt;Um mit dem BAS arbeiten zu können, muss der Dienst zunächst über den Subaccount &lt;strong&gt;abonniert&lt;/strong&gt; werden. Dies setzt voraus, dass im Global Account entsprechende Entitlements vergeben wurden. Die Nutzung ist sowohl im kostenlosen &lt;em&gt;Trial&lt;/em&gt; als auch im &lt;em&gt;Enterprise Account&lt;/em&gt; möglich. Nach der Aktivierung kann direkt mit der Erstellung und Verwaltung von Dev Spaces begonnen werden.&lt;/p&gt;

&lt;h3&gt;Entwicklungsumgebungen nach Szenarien&lt;/h3&gt;

&lt;p&gt;Jede Dev Space Type ist auf ein bestimmtes Anwendungsszenario optimiert. Zum Beispiel beinhaltet ein „SAP Fiori“-Space UI5-Toolkit, OData-Editoren und Deployment-Tools, während ein „CAP“-Space Node.js-basierte CAP-Runtime, SQLite und CDS-Kommandos enthält. Diese maßgeschneiderte Bereitstellung spart Zeit, reduziert manuelle Konfiguration und verbessert die Produktivität erheblich.&lt;/p&gt;



&lt;h2&gt;Deployment in der Cloud Foundry Umgebung&lt;/h2&gt;

&lt;h3&gt;Was ist das Manifest.yml?&lt;/h3&gt;

&lt;p&gt;Beim Deployment von Anwendungen in der Cloud Foundry Umgebung spielt die Datei &lt;strong&gt;manifest.yml&lt;/strong&gt; eine zentrale Rolle. Sie beschreibt die App-Konfiguration, darunter Name, Speicherbedarf, Instanzanzahl, Buildpack, Hostname und Services. Das Manifest automatisiert und standardisiert den Deployment-Prozess, wodurch Fehlerquellen minimiert werden.&lt;/p&gt;

&lt;h3&gt;App-URL und Hostname-Regeln im SAP BTP Umfeld&lt;/h3&gt;

&lt;p&gt;Der Hostname einer App muss innerhalb einer Region eindeutig sein. Eine beispielhafte URL für eine App mit dem Hostnamen &lt;code&gt;myapp&lt;/code&gt; in der Region EU10 lautet: &lt;code&gt;myapp.cfapps.eu10.hana.ondemand.com&lt;/code&gt;. Entwickler:innen sollten bei der Namensgebung daher auf Kollisionen achten oder alternativ mit zufälligen Routen arbeiten.&lt;/p&gt;

&lt;h3&gt;Automatisch generierte Routen mit random-route&lt;/h3&gt;

&lt;p&gt;Ein praktisches Attribut  in der &lt;code&gt;manifest.yml&lt;/code&gt; ist die &lt;code&gt;random-route: true&lt;/code&gt;,  um eine eindeutige Routen-URL generieren zu lassen. Dadurch wird der App-Hostname automatisch um eine zufällige Zeichenfolge erweitert, was die eindeutige Adressierung vereinfacht. Diese Option ist besonders nützlich in Test- und Entwicklungsszenarien, in denen die exakte URL zweitrangig ist.&lt;/p&gt;

&lt;h3&gt;Routing zur Dev Space und Mapping zur App&lt;/h3&gt;

&lt;p&gt;Für den externen Zugriff auf die Anwendung muss eine Route zur entsprechenden Dev Space eingerichtet und mit der App verknüpft werden. Dies erfolgt in der Regel automatisch beim Deployment, kann aber auch manuell angepasst werden. Eine korrekt konfigurierte Route stellt sicher, dass Benutzer:innen und externe Systeme zuverlässig auf die Anwendung zugreifen können.&lt;/p&gt;



&lt;h2&gt;Fazit: Effiziente Entwicklung auf SAP BTP&lt;/h2&gt;

&lt;h3&gt;Zusammenfassung der wichtigsten Punkte&lt;/h3&gt;

&lt;p&gt;SAP BTP bietet eine leistungsstarke und flexible Plattform für die moderne Anwendungsentwicklung in der Cloud. Durch die klare Account-Hierarchie – von Global Account über Subaccount bis zu Spaces – wird eine strukturierte Ressourcennutzung ermöglicht. Mit Tools wie der BTP CLI und dem SAP Business Application Studio lassen sich Entwicklungsprojekte effizient umsetzen, erweitern und verwalten.&lt;/p&gt;

&lt;p&gt;Besonderes Augenmerk sollte auf die korrekte Konfiguration von Entitlements, Quotas und Deployment-Prozessen gelegt werden. Gerade für ABAP-Entwickler:innen eröffnet SAP BTP mit der Steampunk-Umgebung neue Perspektiven für zukunftssichere Cloud-Lösungen.&lt;/p&gt;

&lt;h3&gt;Best Practices für den Einstieg&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;Plane die Account-Struktur frühzeitig und regionsbezogen&lt;/li&gt;
  &lt;li&gt;Nutze Dev Spaces passend zum jeweiligen Anwendungsszenario&lt;/li&gt;
  &lt;li&gt;Verwalte Entitlements zentral über den Global Account&lt;/li&gt;
&lt;/ul&gt;



&lt;h2&gt;Häufig gestellte Fragen (FAQ)&lt;/h2&gt;

&lt;h3&gt;Was ist der Unterschied zwischen einem Subaccount und einer Org in SAP BTP?&lt;/h3&gt;

&lt;p&gt;Ein Subaccount ist Teil der globalen Accountstruktur von SAP BTP und stellt eine Umgebung für Projekte bereit. Innerhalb eines Subaccounts wird automatisch eine Organisation (Org) für die Cloud Foundry Umgebung erstellt, die wiederum in Spaces unterteilt werden kann.&lt;/p&gt;

&lt;h3&gt;Wie kann ich ABAP-Anwendungen auf SAP BTP entwickeln?&lt;/h3&gt;

&lt;p&gt;Dazu wird ein Subaccount mit Cloud Foundry Umgebung benötigt, in dem ein Space für die ABAP Environment angelegt wird. Über das SAP Business Application Studio oder Eclipse ADT können Anwendungen mit dem RAP-Modell entwickelt und bereitgestellt werden.&lt;/p&gt;

&lt;h3&gt;Welche Vorteile bietet die Nutzung von Dev Spaces im Business Application Studio?&lt;/h3&gt;

&lt;p&gt;Dev Spaces sind sofort einsatzbereite, isolierte Entwicklungsumgebungen in der Cloud, die alle nötigen Tools für spezifische Szenarien enthalten – z. B. Fiori, CAP oder ABAP. Das spart Konfigurationszeit und verbessert die Produktivität.&lt;/p&gt;

&lt;h3&gt;Wie funktioniert das Deployment einer App in SAP BTP Cloud Foundry?&lt;/h3&gt;

&lt;p&gt;Das Deployment erfolgt meist über ein &lt;code&gt;manifest.yml&lt;/code&gt;, das die Konfiguration der App beschreibt. Mittels CF CLI kann die App dann in einem bestimmten Space deployed und mit Services wie Logging oder Datenbanken verbunden werden.&lt;/p&gt;

&lt;h3&gt;Was sind Entitlements und warum sind sie wichtig?&lt;/h3&gt;

&lt;p&gt;Entitlements sind Dienst-Berechtigungen, die im Global Account verwaltet und an Subaccounts vergeben werden. Ohne Entitlement kann ein Dienst nicht aktiviert oder genutzt werden – sie sind also essenziell für die Ressourcenplanung.&lt;/p&gt;

</description>
      <category>sap</category>
      <category>cloudnative</category>
      <category>cloudcomputing</category>
      <category>cloudfoundry</category>
    </item>
  </channel>
</rss>
