major
#29948
Credentials für externe Dienste ohne Geheimnisse in der Konfiguration: Secret-Quellen, Token-basierte Authentifizierung (Keycloak/OIDC, Workload Identity, Azure) und API-Gateway
Kontext
Eine TopLogic-Anwendung braucht Zugangsdaten für viele externe Dienste: LLM-Anbieter, Websuche, MCP-Server, A2A-Agenten und Embedding-Dienste (tl-ai-*), DeepL (TranslationService), OpenAPI-Clients und -Server, Mail (SMTP/IMAP), Kafka, JMS (ActiveMQ, IBM MQ), Datenbank-Pool, OIDC-Login (pac4j), LDAP, Azure Blob Storage.
Bisher war jedes dieser Geheimnisse eine String-Property der Konfiguration – entweder als @Encrypted-Wert (nur verschleiert, der Schlüssel liegt daneben) oder über einen ${env:NAME}-Alias aus einer Umgebungsvariablen. Der Wert wurde beim Start einmal aufgelöst; ein Wechsel des Geheimnisses brauchte einen Neustart. Speicherte der Service-Editor eine solche Konfiguration, schrieb er den aufgelösten Wert in die autoconf-Datei, also in den Quellbaum. Auf jedem Entwicklerrechner lagen die echten API-Keys in einer Datei, auch dort, wo ein Coding-Agent sie lesen kann.
Nach diesem Ticket kann eine Anwendung externe HTTP-Dienste aufrufen, ohne selbst einen dauerhaften Provider-Key zu besitzen: Sie weist sich über ihre Identität aus (Keycloak/OIDC, Kubernetes-ServiceAccount, Azure Managed Identity) und bekommt kurzlebige Tokens; die echten API-Keys liegen in einem zentralen Gateway. Wo ein Geheimnis unvermeidbar ist, nennt die Dienstkonfiguration nur seinen Namen; wo die Geheimnisse liegen (Umgebungsvariablen auf dem Entwicklerrechner, Datei-Secrets von Kubernetes/Docker, Azure Key Vault in Produktion), legt jede Installation einmal zentral fest. Gelesen wird zum Zeitpunkt der Nutzung, sodass ein Geheimnis ohne Neustart rotiert werden kann, wo die angebundene Bibliothek das zulässt. Eine Administrationsansicht zeigt alle Geheimnisse der Installation und ob sie verfügbar sind.
Verhalten
Geheimnisquellen
Konfigurationseigenschaften für Geheimnisse sind polymorphe Konfigurationen einer Geheimnisquelle (SecretSource, com.top_logic.basic.credential) statt String. Quellen:
- Geheimnisablage (über den Namen) (NamedSecretSource): die empfohlene Form. Ein Element ohne class nennt das Geheimnis: <api-key name="tl_anthropic_api_key"/>. Wo es liegt, entscheidet die zentrale Geheimnisablage der Installation (siehe unten); ohne eigene Einstellung ist das die gleichnamige Umgebungsvariable.
- Umgebungsvariable (EnvironmentSecretSource, mit class): liest gezielt eine Variable, unabhängig von der zentralen Ablage.
- Datei (FileSecretSource): Kubernetes-/Docker-Secrets, CSI-Driver; wird bei Änderung neu gelesen.
- Wert in der Konfiguration (LiteralSecretSource): die bisherige Attributform. Ein Attributwert wird wie bisher gelesen (verschlüsselt, unencrypted:… oder Alias), bestehende Konfigurationen laden unverändert.
- Azure-Key-Vault-Geheimnis (KeyVaultSecretSource, Modul tl-credential-azure, Anmeldung über Managed Identity).
- Kodierter Wert in der Konfiguration für das LDAP-Master-Credential in der bisherigen CryptSupport-Form (CryptSupportSecretSource).
Quellen mit class sind die Ausnahme für ein einzelnes Geheimnis, das an einem festen Ort liegen muss.
Eine Variable, aus der ein Geheimnis gelesen wird, enthält den reinen Wert; die bisherige Form mit dem Präfix unencrypted: wird weiterhin akzeptiert (das Präfix wird entfernt), sodass bestehende Umgebungen ohne Änderung weiterlaufen. Verschlüsselte Werte in Variablen werden nicht unterstützt.
Der Service-Editor zeigt für ein Geheimnis die Auswahl der Quelle und wählt „Geheimnisablage (über den Namen)“ vor. Gespeichert wird immer der Verweis (Name, Variablenname, Dateipfad) oder ein verschlüsselter Wert, nie ein aufgelöstes Geheimnis. Der Token-Editor (Zufallstoken erzeugen, löschen) funktioniert für ein Geheimnis aus der Konfiguration und wird über @PropertyEditor(TokenEditor.class) an der Eigenschaft gewählt; der OpenAPI-API-Key nutzt ihn.
Zentrale Geheimnisablage
Wo die benannten Geheimnisse liegen, unterscheidet sich von Installation zu Installation (Entwicklerrechner, internes Testsystem, Test- und Produktivsystem des Kunden), ist aber innerhalb einer Installation meist für alle Geheimnisse gleich. Deshalb wird es einmal pro Installation im Dienst „Zentrale Geheimnisablage“ (SecretStoreService) festgelegt statt an jeder Geheimnis-Eigenschaft; die Dienstkonfigurationen sind in allen Installationen gleich. Der Dienst wird wie jeder andere im Service-Editor angezeigt und bearbeitet.
- Ablage (store): EnvironmentSecretStore (Standard: Umgebungsvariable bzw. Systemproperty mit dem Namen des Geheimnisses), DirectorySecretStore (Datei mit dem Namen des Geheimnisses in einem Verzeichnis, z. B. /run/secrets oder ein Kubernetes-Secret-Volume; ein Pfad mit ~/ liegt im Home-Verzeichnis des Benutzers), LiteralSecretStore (verschlüsselte Werte in der Konfiguration selbst, für Testsysteme ohne Secret-Infrastruktur), ChainSecretStore (mehrere Ablagen nacheinander; die erste, die das Geheimnis hat, liefert es) und KeyVaultSecretStore (Modul tl-credential-azure: alle Geheimnisse in einem Azure Key Vault; _` im Namen wird zu `-).
- Jede Ablage kennt ein Präfix (prefix), sodass sich mehrere Installationen eine Ablage teilen können.
- Ausnahmen (overrides): ein einzelnes Geheimnis kann einer beliebigen Geheimnisquelle zugeordnet werden, auch als Alias eines anderen Namens.
- Die Installation speichert die Dienstkonfiguration über den Service-Editor (autoconf) oder legt sie in einem eigenen Konfigurationsfragment ab (tl_config); dessen Ablage ersetzt die der Engine, seine Ausnahmen kommen zu denen der Engine hinzu.
- Die Engine liefert keine Vorgabewerte für Geheimnisse aus: Fehlt in einer Installation ein Geheimnis, wird das sichtbar (Übersicht, Fehlermeldung), statt dass ein öffentlich bekannter Wert verwendet wird.
- Entwicklungsgeheimnisse: Eine lokale Entwicklungsinstallation trägt devel-secrets.xml in die metaConf.txt von deploy/local ein. Dessen Konfiguration in com.top_logic.basic setzt die Ablage auf „Umgebungsvariable, dann Datei im Ordner ~/.top-logic/secrets des Entwicklers, dann Wert in der Konfiguration“. Der Ordner im Home-Verzeichnis gilt für alle Arbeitsbereiche und Anwendungen des Entwicklers und liegt außerhalb jedes Repositorys, z. B. ~/.top-logic/secrets/translation_api_key für DeepL; fehlt er, fehlen seine Geheimnisse. Die Variable tl_devel_secrets_dir verlegt den Ordner. In der Konfiguration steht nur das Passwort der H2-Entwicklungsdatenbank (h2_passwd), sodass ein frischer Checkout ohne Einrichtung startet. devel-*-Dateien werden nicht in ein WAR übernommen; eine ausgelieferte Anwendung liest nur ihre eigene Ablage. Alle lokal startbaren Module und Anwendungen der Engine und der Archetyp für neue Anwendungen tragen die Datei ein.
Übersicht der Geheimnisse
Die Administration (React-Oberfläche) zeigt unter System → Geheimnisse alle Geheimnisse, auf die die Konfigurationen der laufenden Dienste verweisen, auch verschachtelte (z. B. der Schlüssel in den credentials eines LLM-Anbieters), gruppiert nach Dienst: Pfad der Eigenschaft, Quelle, Verweis (Name, Variable, Datei, Vault-Geheimnis; ein Wert in der Konfiguration nur als solcher gekennzeichnet), was ein benanntes Geheimnis auflöst (Ausnahme oder Ablage) und den Status Verfügbar, Fehlt (die Ablage hat das Geheimnis nicht, Variable nicht gesetzt, Datei fehlt) oder Fehler (z. B. leere Datei, Zugriff auf den Key Vault verweigert) mit Meldung. Fehlende und fehlerhafte Geheimnisse sind farblich markiert; „Aktualisieren“ prüft erneut. Der Wert eines Geheimnisses wird weder angezeigt noch an den Browser übertragen.
Fehlende Geheimnisse beim Start, fehlgeschlagene Anmeldung
Ein fehlendes Geheimnis verhindert den Start der Anwendung nicht, wo die Anwendung ohne den betroffenen Teil arbeiten kann: Der Verbraucher liest das Geheimnis erst bei Benutzung, die Übersicht zeigt es als fehlend. Das gilt insbesondere für das Client-Secret eines OIDC-Logins (pac4j): Es wird bei jedem Login-Start und vor jeder Token-Anfrage gelesen; ein geändertes Secret wird ohne Neustart übernommen. Solange es fehlt, bietet der Anmeldedialog diesen Login nicht an (die Verfügbarkeit wird bei jeder Anzeige des Dialogs geprüft), und ein direkter Aufruf des Login-Pfads führt zurück zum Anmeldedialog. Den Start verhindern weiterhin der Pepper des Passwort-Hashings (Argon2) und der Connection-String des Azure-Blob-Speichers, ohne die die Anwendung nicht korrekt arbeiten kann.
Scheitert eine Anmeldung über einen externen Identitätsanbieter – etwa weil er die Client-Credentials der Anwendung ablehnt (unauthorized_client bei falschem Client-Secret), nicht erreichbar ist oder die Authentifizierung mit einem Fehler beantwortet –, führt sie zum Anmeldedialog statt zu einem internen Fehler. Der Dialog zeigt die Meldung „Die Anmeldung über den externen Identitätsanbieter ist fehlgeschlagen. …“, bis der Benutzer sie schließt; die Ursache steht als Warnung im Log. Ein erneuter Klick auf die Anmeldeschaltfläche startet einen neuen Versuch (zuvor lehnte pac4j den zweiten Versuch in derselben Sitzung mit einer 401-Fehlerseite ab). Die Meldung erscheint ebenso für die übrigen Fehler einer externen Anmeldung (Anmeldung verweigert, Wartungsmodus), die bisher in der React-Oberfläche ohne Hinweis zum Anmeldedialog zurückführten.
LDAP und OpenID Connect im WAR aktivieren
Da die Zugangsdaten jetzt aus der Umgebung kommen, braucht eine Installation für LDAP oder einen OpenID-Connect-Login nur noch die Konfiguration des Verfahrens in ihrer metaConf.txt. Diese schaltet ein Maven-Profil von tl-parent-app beim Bau des WARs zu:
- with-ldap: ldapConf.xml (Anmeldung über und Benutzerabgleich mit einem LDAP-Verzeichnis; Einstellungen aus ldap_url, ldap_principal, ldap_credential, ldap_base_dn, ldap_filter, ldap_group_1 … ldap_group_3, ldap_mapping_*).
- with-openid-keycloak, with-openid-azure, with-openid-google, with-openid-generic: die Client-Konfiguration des jeweiligen Anbieters (pac4j-<anbieter>.xml) samt Modul tl-security-auth-pac4j.
Die Profile lassen sich untereinander und mit einem Datenbankprofil kombinieren, z. B. -P with-postgresql,with-ldap,with-openid-keycloak,with-openid-azure. Das Profil bos von tl-parent-app-internal (BOS-Konfigurationsfragmente bos-ldap/`bos-deepl` der Version 7.8.1 mit Zugangsdaten im Fragment) entfällt.
Credential-Provider für HTTP-Dienste
Ein HTTP-Konsument hat eine Eigenschaft credentials (CredentialProvider), die jede Anfrage authentifiziert. Wo der Dienst einen statischen Key erwartet, bleibt api-key als Kurzform erhalten; beides zugleich ist ein Konfigurationsfehler. Auf eine 401-Antwort holt der Konsument einmal frische Credentials und wiederholt die Anfrage (der OpenAPI-Client wiederholt nicht, der nächste Aufruf bekommt ein neues Token). Arten:
- statischer Key aus einer Geheimnisquelle im Header (HeaderCredentials) oder als Basic Auth (BasicCredentials),
- OAuth2/OIDC Client Credentials (ClientCredentialsProvider) gegen einen Token-Endpunkt (z. B. Keycloak) mit client_secret, private_key_jwt (RFC 7523) oder einem Kubernetes-ServiceAccount-Token als client_assertion (Workload Identity); Token-Cache mit Erneuerung vor Ablauf, Discovery über den Issuer,
- Azure Managed Identity (IMDS, App Service, AKS Workload Identity),
- Device-Login (RFC 8628) für die Entwicklung: einmalige Bestätigung im Browser, danach ein persönliches Refresh-Token in einer nur für den Besitzer lesbaren Datei,
- keine Authentifizierung (ein Gateway setzt die Credentials ein).
Umgestellte Konsumenten
- LLM-Anbieter (tl-ai-core) einschließlich Modellabfrage; Websuche (Brave, Tavily), MCP-Client, Gitea-Tool, A2A-Remote-Agenten, Embedder (tl-ai-index), Vektorindex (tl-ai-vector-index). Ohne Key bleibt der Vektorindex deaktiviert und meldet eine Warnung, statt den Start abzubrechen.
- LLM-Proxy der Steueranwendung (tl-factory): Er authentifiziert die weitergeleiteten Anfragen der Workspaces mit den Credentials des konfigurierten Anthropic-Anbieters (API-Key oder credentials), gelesen bei jeder Anfrage. Sind sie nicht verfügbar, antwortet der Proxy mit 503, ohne weiterzuleiten; auf eine 401-Antwort des Anbieters verwerfen die Credentials ihren Cache.
- DeepL (TranslationService).
- OpenAPI-Client und -Server: API-Keys, Passwörter, Client-Secrets; der OAuth-Client-Credentials-Ablauf des Clients nutzt ClientCredentialsProvider statt eigener Token-Logik. Der Server vergleicht Keys und Passwörter in konstanter Zeit.
- Datenbank-Passwort und weitere geheime Treiberoptionen (jede neue physische Verbindung liest das aktuelle Geheimnis; eine Option, deren Geheimnis nicht gesetzt ist, wird weggelassen und im Log mit Name und Verweis gemeldet), SMTP und IMAP (je Verbindung; ohne gesetztes Passwort wird ohne Passwort angemeldet), pac4j-Client-Secret (bei Benutzung, siehe oben), Argon2-Pepper (einmal beim Start), Kafka-Client-Geheimnisse, JMS-Passwörter (je Verbindungsaufbau), LDAP-Master-Credential (je Verbindung), Azure-Blob-Connection-String.
- Die ausgelieferten Konfigurationen der Engine verweisen auf benannte Geheimnisse statt auf Aliase (siehe Migration).
Gateway
Der Entwickler-Artikel credentials/gateway beschreibt einen zentralen Reverse-Proxy (nginx + oauth2-proxy), der das Keycloak-Token der Anwendung prüft (Signatur, Audience, Rolle) und pro Route den echten Key des Dienstes einsetzt. Ein lauffähiges Beispiel liegt in tl-ai-demo/gateway/ (docker compose). Die Anwendung trägt die Gateway-URL als Basis-URL ein und authentifiziert sich mit Client Credentials oder Device-Login. Der Betrieb des Gateways ist nicht Teil des Tickets.
Technische Hinweise
- Die Schnittstellen sowie Geheimnisablage (über den Namen), Umgebungsvariable, Datei, Wert in der Konfiguration, die Ablagen (außer Key Vault), der Dienst SecretStoreService, Header, Basic Auth und "keine Authentifizierung" liegen in com.top_logic.basic (com.top_logic.basic.credential), ohne externe Abhängigkeiten.
- Ein benanntes Geheimnis wird über den gestarteten SecretStoreService aufgelöst. Jeder Dienst, der Geheimnisse liest (auch verschachtelt, z. B. in credentials), deklariert @ServiceDependencies(SecretStoreService.Module.class); ist der Dienst nicht gestartet, meldet das Lesen einen Fehler, der die fehlende Abhängigkeit nennt. Die Engine-Dienste mit Geheimnissen (Verbindungspools, Übersetzung, Mail, LDAP, Passwort-Hashing, Kafka, JMS, pac4j, OpenAPI, Data-Access/Azure-Blob, die Dienste der tl-ai-*-Module) haben diese Abhängigkeit.
- Die Übersicht sammelt die Verweise generisch aus den Konfigurationen der laufenden Dienste (SecretReferences, SecretReference; Eigenschaften mit SecretSourceFormat) und prüft jede Quelle einmal über SecretSource#lookup() (liefert null, wenn das Geheimnis fehlt) und SecretSource#reference() (Beschreibung ohne Wert). Die Ansicht nutzt die TL-Script-Funktionen secret… (SecretFunctions) und eine normale <table>.
- pac4j (6.5.9) leitet aus dem Client-Secret beim ersten Gebrauch die Client-Authentifizierung und den ID-Token-Validator ab und hält sie. OidcClientSecret liest das Secret vor jedem Login-Start und jeder Token-Anfrage und lädt bei einem geänderten Wert die Provider-Metadaten neu, damit pac4j den neuen Wert verwendet. LoginMethod#isAvailable() (Standard true) erlaubt jedem Login-Verfahren, sich vorübergehend abzumelden; LoginMethods.all() liefert nur verfügbare Verfahren, und der Anmeldedialog (LoginMethodsElement) fragt sie bei jeder Anzeige neu ab.
- Fehler einer Anmeldung über pac4j fangen die Callback- und die Security-Logik von pac4j (LoginFailureLogic.Callback/`.Security`, in Pac4jConfigFactory gesetzt) ab: Sie protokollieren die Ursache und leiten über die Fehler-URL von pac4j auf die Seite loginRetrySSO der ApplicationPages um. Antworten, die pac4j bewusst sendet (z. B. die Weiterleitung zum Identitätsanbieter), bleiben unverändert. Die Prüfung checkAuthenticationAttempt von pac4j (Schutz vor Weiterleitungsschleifen) ist für die Login-Clients abgeschaltet, da ein Fehler zum Anmeldedialog führt und der Benutzer bewusst erneut startet.
- Den Fehler einer externen Anmeldung meldet der erkennende Code als ExternalLoginFailure in der HTTP-Sitzung (pac4j-Logik und alle Fehlerzweige von ExternalAuthenticationServlet); LoginMethodsElement (<login-methods/>) entnimmt ihn beim Schreiben und zeigt ihn als schließbare Fehlermeldung (ReactAlertControl) über den Anmeldeschaltflächen.
- Die Profile von tl-parent-app setzen je eine eigene Eigenschaft tl.app.metaConfAddons.<name>: die Datenbankprofile tl.app.metaConfAddons.db (Vorgabe db-jndi.xml, immer eine Datenbank), die Profile für LDAP und OpenID Connect z. B. tl.app.metaConfAddons.ldap. Das Ziel app des tl-maven-plugin (TLAppWar#metaConfAddons) fügt zuerst die Verweise von tl.app.metaConfAddons (frei für eigene Verweise der Anwendung) und dann die aller Eigenschaften mit diesem Präfix, nach Namen sortiert, in die metaConf.txt ein; bisher konnte nur ein Profil Verweise beitragen.
- Die Managed Identity, Key-Vault-Quelle und Key-Vault-Ablage im Modul tl-credential-azure nutzen das Azure SDK (azure-identity, azure-security-keyvault-secrets) über den HTTP-Client des JDK (ohne Netty); Quelle und Ablage teilen sich Client und Cache (ein nicht vorhandenes Geheimnis wird als „fehlt“ zwischengespeichert, andere Fehler nicht). Ein Neuladen des Tokens nach 401 erneuert bei AKS Workload Identity sofort; bei IMDS und App Service hält das SDK ein gültiges Token bis 5 Minuten vor Ablauf.
- Die OAuth-Provider (Client Credentials, Device-Login) liegen im Modul tl-credential-oauth und nutzen für das Protokoll das Nimbus OAuth 2.0 SDK (oauth2-oidc-sdk, nimbus-jose-jwt), das bereits über pac4j und die OpenAPI-Module verwendet wird. Eigener Code beschränkt sich auf Konfiguration, Token-Cache, Refresh-Token-Datei und Fehlermeldungen.
- @ImplementationClassDefault darf an einem Typ stehen; SecretSource legt damit NamedSecretSource als Standardklasse fest (Einlesen, Schreiben, Vorauswahl im Editor).
- Der Service-Editor liest eine gespeicherte Konfiguration vor dem Schreiben mit aufgelösten Aliasen ein; zuvor brach das Speichern ab, wenn die Datei einen Alias in einem verschlüsselten Wert enthielt.
- Entwickler-Kapitel credentials (com.top_logic.basic): Überblick, Geheimnisquellen, Geheimnisablagen, Credential-Provider, Gateway, Keycloak-Einrichtung, Migration. Die Profile beschreibt der Artikel application-project (com.top_logic).
- Aliase im formatierten Elementinhalt einer Eigenschaft (z. B. <secret>%PAC_SECRET%</secret> der pac4j-Konfigurationen) werden aufgelöst; zuvor geschah das nur in Attributen und im Elementtext einfacher Werte, sodass ein Geheimnis als Elementinhalt mit Alias beim Einlesen nicht entschlüsselt werden konnte.
- Gefunden und als eigenes Ticket erfasst: #29954 (Modellkatalog aus der Dienstkonfiguration des LLM-Anbieter-Dienstes herausnehmen).
Migration
Bestehende Konfigurationen als Attribut oder Elementinhalt (api-key="unencrypted:…", verschlüsselte Werte, Aliase) laden unverändert. Zu ändern ist:
- Ausgelieferte Konfigurationen der Engine: Sie verweisen auf benannte Geheimnisse; die gleichnamigen Variablen bleiben gültig: Datenbank-Passwörter h2_passwd, db2_passwd, mssql_passwd, mysql_passwd, oracle_passwd, postgresql_passwd (sowie die optionalen Truststore-/Keystore-Passwörter von MSSQL und MySQL), ldap_credential, smtp_pass, imap_pass, tl_pac_secret, blob_connect. Die Aliase %H2_PASSWD%, %DB2_PASSWD%, %MSSQL_PASSWD%, %MYSQL_PASSWD%, %ORACLE_PASSWD%, %POSTGRESQL_PASSWD%, die Truststore-/Keystore-Aliase, %LDAP_CREDENTIAL%, %SMTP_PASS%, %IMAP_PASS%, %PAC_SECRET%, %BLOB_CONNECT%, %BLOB_USER% und %BLOB_PASS% entfallen; eine Anwendung, die einen davon selbst definiert oder verwendet hat, stellt auf die benannte Form um (z. B. <encrypted-option name="password"><value name="h2_passwd"/></encrypted-option>).
- Keine Vorgabewerte mehr: Die bisherigen Alias-Vorgaben gelten nicht mehr. Insbesondere muss eine ausgelieferte Installation mit H2, die sich auf das Standardpasswort verlassen hat, h2_passwd setzen, und eine Installation mit dem pac4j-Demo-Client tl_pac_secret (ohne es bietet der Anmeldedialog den Keycloak-Login nicht an).
- Entwicklungsinstallation einer Anwendung: Eine Anwendung, die lokal mit H2 gestartet wird, trägt devel-secrets.xml in deploy/local/webapp/WEB-INF/conf/metaConf.txt nach devel-h2.xml ein; ohne den Eintrag liest sie h2_passwd nur aus der Umgebung, und die mit dem Passwort password angelegte Datenbank ./tmp/h2 lehnt die Anmeldung ab. Eigene Schlüssel, die ein Entwickler bisher als Variable gesetzt hat (z. B. translation_api_key), kann er als Datei in ~/.top-logic/secrets ablegen oder weiter als Variable setzen.
- Profil bos entfällt: Ein Bau mit -P bos (interne Testinstallationen) aktiviert LDAP nicht mehr; Maven 3.9 überspringt das unbekannte Profil mit einer Warnung. Ersatz ist -P with-ldap mit den LDAP-Einstellungen und ldap_credential (reiner Wert) aus der Umgebung, für DeepL translation_api_key und translation_enabled=true.
- Datenbank im WAR: Die Datenbankprofile von tl-parent-app (with-h2, with-mysql, …) setzen tl.app.metaConfAddons.db statt tl.app.metaConfAddons. Ein Bau, der die Datenbank direkt über tl.app.metaConfAddons gewählt hat (z. B. -Dtl.app.metaConfAddons=db-h2.xml oder als Eigenschaft der Anwendung), setzt stattdessen tl.app.metaConfAddons.db; sonst kommt die Vorgabe db-jndi.xml hinzu.
- Inhalt der Variablen: Eine Variable enthält den reinen Wert; die bisherige Form mit unencrypted: wird weiter akzeptiert. Verschlüsselte Werte in Variablen werden nicht unterstützt.
- Geheimnisablage einer Installation: Ohne eigene Einstellung liest ein benanntes Geheimnis die gleichnamige Umgebungsvariable. Eine Installation, die ihre Geheimnisse anders ablegt (Verzeichnis, Key Vault), konfiguriert den Dienst SecretStoreService (Service-Editor oder eigenes Konfigurationsfragment). Ein Geheimnis, das dann trotzdem aus einer Umgebungsvariable kommen soll, bekommt eine Ausnahme (overrides) oder die explizite Form <… class="com.top_logic.basic.credential.EnvironmentSecretSource" name="…"/>.
- Eigene Dienste mit Geheimnissen: Ein Dienst einer Anwendung, der ein benanntes Geheimnis liest, deklariert @ServiceDependencies(SecretStoreService.Module.class); Tests solcher Dienste starten den SecretStoreService mit.
- MCP-Client: bearer-token-env-var entfällt. Ersatz:
<credentials class="com.top_logic.basic.credential.HeaderCredentials" scheme="Bearer"> <secret name="MY_MCP_TOKEN"/> </credentials>
Ein HttpMcpTransport braucht mcp-json-jackson3 im Klassenpfad (bringt tl-ai-mcp-server mit).
- A2A-Remote-Agent: token-env entfällt; Ersatz ist dieselbe credentials-Form.
- Vektorindex: mistral-api-key="%MISTRAL_API_KEY%" ohne Präfix wird zu <mistral-api-key name="tl_mistral_api_key"/>; die Alias-Definition in tl-ai-vector-index entfällt.
- API-Änderungen für Entwickler: DataSourceConfig.getDriverOptions() liefert Map<String, AbstractDriverOption>; ServiceProviderInfo.createFromConfig(Config) und withCredentials(String); die Getter umgestellter Geheimnis-Eigenschaften liefern PolymorphicConfiguration<? extends SecretSource>; ein Element ohne class liest sich als NamedSecretSource.Config (nicht EnvironmentSecretSource.Config); GiteaIssueTool.TOKEN_SECRET statt TOKEN_VARIABLE; Pac4jLoginMethod erhält seinen ClientConfigurator im Konstruktor; ReflectiveToolFactory akzeptiert <tool class=…>; im OpenAPI-Client entfallen HTTPAuthenticationEnhancer, ClientCredentialEnhancer und TokenBasedEnhancer; LLMUpstream (tl-factory) trägt einen CredentialProvider statt des API-Keys, LLMUpstream.fromProvider nimmt den gestarteten AnthropicProviderConfig (LLMProviderService#getProvider(String)); ExternalAuthenticationServlet.forwardToSSOLoginFailed erhält die Meldung als ResKey; der Konstruktor LoginMethodsElement(String, Supplier, Supplier) erhält zusätzlich die Quelle der Fehlermeldung; I18NConstants.ERROR_NTLM_AUTHEMTICATION_FAILED (com.top_logic.base.accesscontrol) entfällt zugunsten von ERROR_EXTERNAL_LOGIN_FAILED.
Die vollständige Beschreibung mit Vorher/Nachher-Beispielen steht in den Entwickler-Artikeln credentials/migration und credentials/secret-stores.