Connection Strings gehören nicht in den Code - erst recht nicht mit KI

Rohit Birdi 07. November 2026 32 Aufrufe

Was im Code steht, liest die KI mit. So halten wir DB Connection Strings mit Environment Variablen und Managed Identity aus dem Repo und warum nicht im Key Vault.

← Zurück zum Blog

Claude Code arbeitet bei uns direkt im Projekt mit: liest Code, Configs, eigentlich alles im Repo. Ist ja auch so gewollt, sonst kann die KI nicht helfen. Heißt aber auch: Was im Code steht, landet im Kontext der KI. Deshalb gilt bei uns eine klare Regel: Sensible Sachen wie der Connection String zur Datenbank haben im Code nichts verloren. In diesem Beitrag zeige ich euch, wie wir das mit Environment Variablen lösen und warum wir den DB Connection String bewusst nicht im Key Vault ablegen.

Das Problem: Der hartkodierte Connection String

So sollte man es nicht machen:

var connectionString = "Server=prod-sql.database.windows.net;Database=Analyzer;User Id=sqladmin;Password=Sup3rGeheim!";
builder.Services.AddDbContext<AnalyzerDbContext>(options => options.UseSqlServer(connectionString));

Oder etwas versteckter in der appsettings.json:

{
  "ConnectionStrings": {
    "DBConnectionString": "Server=prod-sql.database.windows.net;Database=Analyzer;User Id=sqladmin;Password=Sup3rGeheim!"
  }
}

War schon immer eine schlechte Idee. Mit KI wird es aber nochmal gefährlicher:

  • Die KI liest mit: Sobald sie die Datei öffnet, ist das Passwort Teil vom Chat, vom Verlauf und eventuell von Logs.
  • Die KI kopiert Muster: Der String taucht plötzlich auch in Tests, Skripten und Beispielen auf.
  • Der Agent kann sich verbinden: Ein Agent, der Befehle ausführt, könnte sich damit einfach auf die Prod DB verbinden, z.B. für einen "kurzen Check".
  • Git vergisst nicht: Ein Commit und das Passwort ist für immer in der Git Historie, auch wenn ihr die Zeile später löscht.

Die Lösung: Environment Variablen

ASP.NET Core liest Environment Variablen automatisch in die Configuration ein. Aus ConnectionStrings__DBConnectionString (zwei Unterstriche!) wird ConnectionStrings:DBConnectionString. Im Code steht dann nur noch der Name, nie der Wert:

var connectionString = builder.Configuration.GetConnectionString("DBConnectionString");
var useInMemory = string.IsNullOrWhiteSpace(connectionString);

if (useInMemory && !builder.Environment.IsDevelopment())
    throw new InvalidOperationException("ConnectionStrings__DBConnectionString ist nicht gesetzt.");

Fehlt die Variable in der Cloud, crasht die App direkt beim Start mit einer klaren Meldung. Viel besser als irgendein kryptischer Fehler später zur Laufzeit. Lokal ist ein leerer Wert dagegen gewollt, dazu gleich mehr.

Der größte Vorteil: Lokal leer, in der Cloud befüllt

Lokal legen wir die Variable in der launchSettings.json an, lassen sie aber leer:

{
  "profiles": {
    "Kunde.Analyzer": {
      "commandName": "Project",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "ConnectionStrings__DBConnectionString": ""
      }
    }
  }
}

Befüllt wird sie erst in der Cloud, z.B. in den Umgebungsvariablen vom App Service in Azure oder über die Pipeline. Kleiner Tipp: Im App Service könnt ihr den Wert entweder als App Setting ConnectionStrings__DBConnectionString anlegen oder im Bereich "Verbindungszeichenfolgen" mit dem Namen DBConnectionString. ASP.NET Core findet ihn in beiden Fällen.

Heißt: Auf dem Entwicklerrechner gibt es den echten Connection String gar nicht. Claude Code kann ihn nicht lesen, nicht kopieren und nicht aus Versehen benutzen, weil er einfach nicht da ist. Trotzdem sieht jeder sofort, welche Variablen die App braucht, nur eben ohne Werte.

Und womit arbeiten wir lokal? Mit der EF Core InMemory Database. Ist der Connection String in Development leer, nimmt die App automatisch die InMemory DB. Wie das genau funktioniert, zeigen wir euch in einem anderen Beitrag ;)
Das Wichtigste: Prod Werte kommen nie auf den Rechner.

Was ist mit Key Vault?

In unserem Beitrag Wohin mit meinen Zugangsdaten? Azure Key Vault einfach erklärt haben wir euch den Key Vault ja schon ans Herz gelegt. Und dafür stehen wir auch:

  • Für Secrets und Keys für andere Systeme macht Key Vault absolut Sinn: API Keys von Drittanbietern, Zertifikate, Tokens.
  • Zentral verwaltet, rotierbar, und jeder Zugriff wird geloggt.

Beim DB Connection String der eigenen App sehen wir das aber differenzierter. Die App läuft ohne Datenbank sowieso nicht. Holt sie sich den Connection String beim Start aus dem Key Vault, kommt eine Abhängigkeit dazu:

  • Key Vault nicht erreichbar oder Berechtigung fehlt -> kein Connection String
  • Kein Connection String -> keine DB
  • Keine DB -> App startet nicht, obwohl die DB eigentlich problemlos läuft

Fairerweise: Key Vault ist sehr verfügbar, und mit Key Vault Referenzen im App Service wird der Wert zwischengespeichert. Ein Totalausfall ist also selten. Trotzdem ist es ein System mehr, das man konfigurieren, berechtigen und im Fehlerfall debuggen muss. Dafür verzichtet ihr bei der Env Variable auf Zugriffs Logs und Rotation, und jeder mit Contributor Rechten auf die App kann den Wert sehen. Das solltet ihr bewusst abwägen.

Bei uns liegt der Connection String deshalb als Env Variable direkt in der Cloud Umgebung der App. Und damit dieser Nachteil gar nicht erst ins Gewicht fällt, gehen wir noch einen Schritt weiter.

Noch besser: Gar kein Passwort im Connection String

Mit einer Managed Identity braucht eure App für Azure SQL überhaupt kein Passwort mehr. Der Connection String sieht dann so aus:

Server=tcp:prod-sql.database.windows.net;Database=Analyzer;Authentication=Active Directory Default;Encrypt=True;

Kein User, kein Passwort. Die App meldet sich mit ihrer eigenen Identität in Entra ID an. Dafür aktiviert ihr im App Service die Managed Identity und legt in der Datenbank einen User dafür an:

CREATE USER [app-kunde-analyzer] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [app-kunde-analyzer];
ALTER ROLE db_datawriter ADD MEMBER [app-kunde-analyzer];

Wenn sich die App beim Start selbst migriert, braucht sie zusätzlich z.B. db_ddladmin. Ab jetzt ist der Connection String kein Geheimnis mehr. Selbst wenn er irgendwo auftaucht, kann niemand ohne die Identität der App etwas damit anfangen. Zack!

Und wenn doch Secrets lokal liegen?

Manchmal geht es nicht anders und ein Secret liegt lokal in einer .env Datei, z.B. ein API Key für eine Testumgebung. Dann nehmt der KI die Berechtigung, diese Dateien zu lesen. In Claude Code geht das über die .claude/settings.json im Projekt:

{
  "permissions": {
    "deny": [
      "Read(./.env)",
      "Read(./.env.*)",
      "Read(./secrets/**)"
    ]
  }
}

Achtung: Diese Regeln greifen für die Datei Tools von Claude Code. Darf der Agent Shell Befehle ausführen, kommt er mit einem simplen cat .env eventuell trotzdem ran. Sichert also auch die Shell Befehle ab oder nutzt die Sandbox. Andere Tools wie Codex haben eigene Einstellungen dafür, schaut da am besten in die jeweilige Doku. Am sichersten bleibt aber: Was nicht auf dem Rechner liegt, kann auch nicht gelesen werden ;)

Fazit

Connection Strings gehören nicht in den Code und erst recht nicht in die Reichweite eurer KI. Bei uns sieht das so aus:

  • Im Code steht nur der Name der Variable, nie der Wert.
  • Lokal ist die Variable leer, die App läuft mit der InMemory DB.
  • In der Cloud ist sie befüllt, am besten ohne Passwort über eine Managed Identity.
  • Fehlt sie in der Cloud, crasht die App sofort beim Start.
  • Key Vault nutzen wir für Secrets von Drittsystemen, nicht als zusätzliche Hürde vor der eigenen Datenbank.

Ganz einfach, und Claude Code kann frei arbeiten, ohne jemals ein Prod Passwort zu sehen.

Der Text dieses Beitrags wurde mithilfe von KI sprachlich überarbeitet und korrigiert.

Dieser Beitrag wurde 32 mal aufgerufen – Wie findest du diesen Beitrag?

Kommentare

Kommentar hinterlassen

Kommentare werden moderiert und bei Regelverstößen oder Missbrauch ausnahmslos entfernt.