# Secrets

Wie Beeuni Projektzugangsdaten speichert und kontrolliert, ob Agentencode die einzelnen Werte lesen kann.

Canonical page: https://beeuni.ai/docs/de/project/secrets

Ein Geheimnis ist eine projektbezogene Zugangsdatenangabe – ein API-Schlüssel, Token oder eine Verbindungszeichenfolge –, die eine Sitzung benötigt, die aber nicht im Repository liegen darf.
Beeuni speichert Geheimnisse beim Projekt, niemals beim Konto, und verschlüsselt jeden Wert mit AES-256-GCM und einem projektspezifisch abgeleiteten Schlüssel.

<a id="identifier-and-name"></a>

## Kennung und Name

Jedes Geheimnis hat zwei Namen. Die `identifier` ist der Bezeichner, den du in der CLI und in der `secrets`-Freigabe eines Agenten verwendest. Der `name` ist der Schlüssel der Umgebungsvariable in Großbuchstaben in der Sandbox, zum Beispiel `STRIPE_API_KEY`. In den meisten Projekten stimmen Kennung und Name überein. Sie unterscheiden sich nur, wenn ein Projekt mehrere mögliche Werte für einen Namen enthält – etwa wenn ein primärer und ein Ersatzschlüssel für Google Maps beide zu `GOOGLE_MAPS_API_KEY` aufgelöst werden können.

Jede Zugriffsregel verwendet die Kennung. Keine davon verwendet den Namen.

<a id="exposure-and-usage"></a>

## Sichtbarkeit und Verwendung

Ein Geheimnis hat zwei unabhängige Einstellungen. Lies sie getrennt; sie beantworten unterschiedliche Fragen.

| Einstellung | Beantwortete Frage | Werte |
|---|---|---|
| **Sichtbarkeit** | Kann Agent-Code den tatsächlichen Wert lesen? | `environment`, `egress-enforced`, `none` |
| **Verwendung** | Wer verbraucht ihn? | Agent-Code, LLM-Gateway, Connector, Git |

Ältere Beeuni-Dokumentation führte beide Einstellungen in einer gemeinsamen Liste auf. Das gibt es nicht mehr. Es gibt keine Wahl zwischen einer „Netzwerkgrenze“ und einem „HTTPS-Broker“: Ein Mechanismus dient allen Geheimnissen mit erzwungener Egress-Kontrolle bei jedem Sandbox-Anbieter.

<a id="the-three-exposures"></a>

### Die drei Sichtbarkeitsstufen

| Sichtbarkeit | Was in der Sandbox liegt | Verwendung |
|---|---|---|
| **Umgebung** | Der tatsächliche Wert als Klartext-Umgebungsvariable | Standard. Werte, mit denen der Agent rechnen muss, und Protokolle, die nicht HTTPS verwenden |
| **Egress-erzwungen** | Ein **Handle** – ein selbsterklärender Platzhalter, der für sich allein wertlos ist | Experimentell. HTTPS-Aufrufe, sobald das `secrets_egress`-Flag aktiviert ist |
| **Keine** | Überhaupt nichts | Zugangsdaten, die nur ein Beeuni-Dienst verwendet, oder ein gespeicherter und deaktivierter Wert |

> **Grundregel**
>
> **Umgebung** ist die standardmäßige Sichtbarkeit. Der tatsächliche Wert wird in die Sandbox geladen, wo der Agent ihn lesen, ausgeben und weiterleiten kann. Bei **Egress-erzwungen** bleibt der Wert außerhalb der Sandbox, aber diese Einstellung ist experimentell: Aktiviere das Feature-Flag `secrets_egress` (Settings → Feature flags), um sie zu verwenden. Bis dahin wird ein Geheimnis in die Sandbox-Umgebung geladen.

<a id="usages"></a>

### Verwendungen

Die meisten Verwendungen werden von Beeuni zugewiesen, nicht von dir:

- **Agent-Code** – gilt automatisch, wenn die Sichtbarkeit nicht `none` ist.
- **LLM-Gateway** – wird zugewiesen, wenn der Wert als Schlüssel eines unterstützten Modellanbieters erkannt wird. Das Gateway authentifiziert Anbieteranfragen serverseitig.
- **Connector:&lt;slug&gt;** – wird durch den Connector-Bindungsablauf zugewiesen.
- **Git** – wird von Beeuni für den eigenen Git-Zugriff zugewiesen. Schreibgeschützt; du kannst diese Verwendung weder festlegen noch entfernen.

Ein Geheimnis mit der Sichtbarkeit `none` und ohne Verwendung wird als **Deaktiviert** angezeigt: gespeichert, verschlüsselt und von nichts verwendet.

<a id="sent-secrets-and-computed-secrets"></a>

## Übermittelte und berechnete Geheimnisse

Welche Sichtbarkeit ein Geheimnis verwenden kann, hängt von der **vorgelagerten Anwendung** ab, nicht von Beeuni.

- **Übermittelte Geheimnisse** – der Wert wird über das Netzwerk übertragen. API-Schlüssel, Bearer-Token, Passwörter. Dies ist bei weitem der häufigste Fall. Der Wert liegt kurzzeitig als Bytefolge in einer ausgehenden Anfrage vor, sodass Beeuni ihn selbst außerhalb der Sandbox einsetzen kann. Ein übermitteltes Geheimnis kann auf **egress-erzwungen** umgestellt werden, sobald das Flag `secrets_egress` aktiviert ist; standardmäßig wird es in die Sandbox-Umgebung geladen.
- **Berechnete Geheimnisse** – der Wert ist Bestandteil einer Berechnung und wird nie übertragen. AWS-SigV4-Signaturschlüssel, HMAC-Geheimnisse zum Signieren von Webhooks, JWT-Client-Assertions, private SSH-Schlüssel. Wer die Berechnung ausführt, muss den Wert besitzen. Eine Netzwerkgrenze hilft nicht, da die Zugangsdaten nicht Teil der übertragenen Daten sind. Berechnete Geheimnisse müssen auf **Umgebung** bleiben.

**Umgebung** ist die standardmäßige Sichtbarkeit und die einzige, die Zugangsdaten bereitstellen kann, mit denen die Sandbox rechnen muss. Nicht-HTTPS-Protokolle – etwa eine Postgres-Verbindungszeichenfolge oder SMTP-Zugangsdaten – müssen ebenfalls auf **Umgebung** bleiben.

Wenn du einen Wert speicherst, der nach Signaturmaterial aussieht, etwa ein `AKIA…`-Zugangsschlüsselpaar oder PEM-/SSH-Material, setzt Beeuni standardmäßig **Umgebung** und erklärt warum: Dieser Schlüssel signiert Anfragen lokal, daher kann die Egress-Kontrolle nicht greifen.

<a id="egress-enforced-exposure"></a>

## Sichtbarkeit „Egress-erzwungen“

> **Experimentell – secrets_egress-Flag erforderlich**
>
> Die Durchsetzung auf Netzwerkebene ist experimentell. Aktiviere das Feature-Flag `secrets_egress` (Settings → Feature flags), um sie zu verwenden. Bis dahin wird ein Geheimnis in die Sandbox-Umgebung geladen. Ist das Flag deaktiviert, führt das Erstellen eines Geheimnisses mit erzwungener Egress-Kontrolle zu `403` `feature_disabled`.

Die Sandbox erhält eine Umgebungsvariable, deren Wert ein **Handle** und nicht die Zugangsdaten selbst ist. Der Agent verwendet diese Variable genau wie den echten Schlüssel – in einem Header, einer Abfragezeichenfolge oder einem Body. `Authorization: Bearer $VAR`, `Cookie: …=$VAR`, ein `X-Api-Key`-Header, ein Abfrageparameter und ein JSON- oder Formularfeld im Body funktionieren alle: Beeuni findet das Handle an jeder Stelle, an der es vorkommt (unverändert, URL-kodiert, als eigenständiger Base64-Wert oder JSON-escaped), und ersetzt es durch den tatsächlichen Wert. Auf dem Weg nach draußen ersetzt Beeuni das Handle durch den tatsächlichen Wert, aber nur bei Anfragen an genehmigte Hosts.

> **Handle unverändert senden – nicht selbst Base64-kodieren**
>
> Eine Sache funktioniert nicht: das Handle in einem Base64-Block zu verstecken, den du selbst erstellst. Genau das macht **HTTP Basic Auth** (`curl -u $VAR:` → `Authorization: Basic <base64>`). Beeuni kann ein Handle nicht finden, wenn es eingebettet und nicht an der richtigen Position steht, innerhalb eines von dir kodierten Base64-Werts. Deshalb findet kein Austausch statt und der vorgelagerte Dienst antwortet mit `401`. Verwende das Handle stattdessen in einem Bearer-/Token-Header, einem Abfrageparameter oder einem Body-Feld. Wenn die API nur Basic Auth unterstützt, verwende für dieses Geheimnis die Sichtbarkeit **Umgebung**.

Daraus ergeben sich folgende Fakten:

- Der tatsächliche Wert gelangt **niemals** in die Sandbox: weder als Umgebungsvariable noch als Datei oder Alias.
- Wird ein Handle an einen nicht genehmigten Host gesendet, kommt es dort als unveränderte Handle-Zeichenfolge an. Der vorgelagerte Dienst lehnt sie ab. Sie ist wertlos.
- Ein Handle mit ungültiger Signatur wird niemals akzeptiert, und Beeuni protokolliert es als gefälschtes Handle. Ein gültiges Handle für ein Geheimnis, das diese Sitzung nicht verwenden darf, wird als gestohlenes Handle protokolliert.
- Für jede weitergeleitete Anfrage wird ein Prüfdatensatz erstellt.
- An Hosts, die nicht auf der Liste stehen, wird der Datenverkehr getunnelt, ohne ihn auszulesen. Clients mit angeheftetem TLS-Zertifikat und mTLS-Clients zu diesen Hosts sind davon nicht betroffen.

<a id="hosts-match-exactly"></a>

### Hosts müssen genau übereinstimmen

Führe jeden Host auf, den du aufrufst – einen exakten Hostnamen pro Zeile.

| Abgelehnt | Grund |
|---|---|
| Ein Wildcard-Host, `*.example.com` | Der Agent darf das Ziel niemals auswählen |
| Ein anderes URL-Schema als HTTPS | Beeuni beendet TLS, um den Wert einzusetzen |

`api.example.com` umfasst `uploads.api.example.com` nicht. Füge den zweiten Host zum selben Geheimnis hinzu. Beeuni lehnt eine nicht durchsetzbare Richtlinie beim Speichern mit `400` ab – eine Regel, die nicht angewendet werden kann, wird niemals gespeichert.

Zwei Egress-geschützte Secrets können denselben Host verwenden. Jeder Handle ist einem eigenen Wert zugeordnet, sodass beide in derselben Anfrage korrekt ersetzt werden.

<a id="verify-it-with-two-probes"></a>

### Mit zwei Prüfungen testen

Führe beide Prüfungen in der Sandbox aus und richte sie an einen Host, der auf der Liste steht. Im Beispiel wird `postman-echo.com` verwendet, das jeweils einen Endpunkt für beide Arten bereitstellt. Füge es für die Dauer des Tests als zulässigen Host hinzu.

```bash
# 1. Reachability — an endpoint that does NOT echo request headers.
curl -s -o /dev/null -w '%{http_code}\n' https://postman-echo.com/status/200
# expected: 200

# 2. Substitution — an endpoint that DOES echo request headers.
curl -sS -H "authorization: Bearer $STRIPE_API_KEY" https://postman-echo.com/get
# expected: 200, with "Bearer [REDACTED]" in the echoed headers
```

Werte die beiden Prüfungen gemeinsam aus und führe Prüfung 1 zuerst aus: Nur sie zeigt dir, ob der Host erreichbar ist. Prüfung 2 sagt nichts aus, solange Prüfung 1 nicht bestanden wurde.

| Ergebnis von Prüfung 2 | Bedeutung |
|---|---|
| `200`, der zurückgesendete Header zeigt `[REDACTED]` | Funktioniert. Der echte Wert wurde an den Upstream gesendet und die Echo-Antwort auf dem Rückweg unkenntlich gemacht. |
| `200`, der zurückgesendete Header zeigt den Handle selbst | Die Ersetzung wurde nicht ausgeführt. Prüfe die Hostliste und die Freigabe für den Agenten. |
| `401` von einem echten API-Host | Die Ersetzung wurde nicht ausgeführt. Prüfe dieselben beiden Punkte. |
| Eine leere Antwort oder ein Verbindungsfehler | Ein echter Fehler. Das ist kein Anzeichen für einen erfolgreichen Ablauf. |

Vergewissere dich, dass der echte Wert nirgendwo in der Gastumgebung vorkommt:

```bash
env | grep '^STRIPE_API_KEY='
# expected: the handle, not the credential
```

Der Bezeichner erscheint auch in `BEEUNI_SECRET_CAPABILITIES`, dem wertfreien Katalog, der dem Agenten mitteilt, welche Secrets existieren, welche Variable welchen Handle enthält und für welche Hosts die einzelnen Secrets gelten. Er enthält niemals einen Wert.

Ein Host auf der Liste präsentiert ein von Beeuni für diese Sandbox ausgestelltes Zertifikat, dem die Sandbox bereits vertraut, anstelle des Zertifikats des Ursprungsservers:

```bash
curl -sv https://postman-echo.com/status/200 2>&1 | grep 'issuer:'
# issuer: CN=Beeuni Egress CA (<project prefix>); O=Beeuni
```

<a id="what-the-relay-changes"></a>

### Was der Relay ändert

Ein genehmigter Host wird über Beeuni aufgerufen und verhält sich daher etwas anders als bei einem direkten Aufruf:

- Antworten werden nicht gestreamt. Server-Sent Events und WebSockets funktionieren über einen genehmigten Host nicht.
- Der Anfrageinhalt ist auf 1 MiB, die Antwort auf 5 MiB und der gesamte Aufruf auf 30 Sekunden begrenzt. Beeuni folgt höchstens 3 Weiterleitungen.
- Zurückgegeben wird nur eine festgelegte Auswahl an Antwort-Headern – Inhaltstyp und Sprache, Cache-Validatoren, die Rate-Limit-Headergruppe, `retry-after`, `x-request-id`.
- Abgefangen werden nur Clients, die `https_proxy` beachten. Beeuni setzt diese Variable und das passende CA-Vertrauen in der Umgebung des Agenten. Ein Prozess, der mit einer bereinigten Umgebung gestartet wird, ruft den Host direkt auf und sendet dabei den Handle mit.

Für Anfragen, die Beeuni nicht abfangen kann, hat der Agent einen direkten Zugang zu denselben Hosts unter denselben Richtlinien:

```bash
beeuni secrets call STRIPE_API_KEY https://api.stripe.com/v1/customers
```

<a id="environment-exposure"></a>

## Verfügbarkeit in der Umgebung

Die Sandbox erhält den echten Wert als einfache Umgebungsvariable. Agentencode kann ihn auslesen, ausgeben und beliebig weiterleiten. Beeuni kann ihn weder unkenntlich machen noch seine Verwendung protokollieren oder verhindern, dass er die Sandbox verlässt.

Die Umgebung ist die standardmäßige Bereitstellungsart. Jedes neue Secret wird so bereitgestellt, es sei denn, du stellst es auf Egress-geschützt um. Diese Funktion ist experimentell und erfordert das Flag `secrets_egress`. Ein berechneter Zugangsschlüssel und alle Protokolle außer HTTPS müssen in der Umgebung bleiben.

<a id="who-can-use-a-secret"></a>

## Wer ein Secret verwenden kann

Für jeden Secret-Wert gilt eine Zielgruppe – dieselbe Auswahl **Wer kann es verwenden** wie bei einem Connector-Konto:

| Auswahl | Wer den Wert verwenden kann |
| --- | --- |
| **Alle im Projekt** (Standard) | Jede Sitzung im Projekt, einschließlich Triggern, geplanten Ausführungen und geteilten Sitzungen. |
| **Nur du** | Du selbst und deine eigenen privaten Sitzungen. |
| **Bestimmte Personen, Gruppen oder Agenten** | Die ausgewählten Personen und Gruppen (direkt und in ihren eigenen privaten Sitzungen) sowie die ausgewählten Agenten (in all ihren Sitzungen). |

Eine Sitzung ist immer zugleich mit ihrem **Agenten** verknüpft und – aber nur, solange sie privat ist – mit ihrer **Person**.

- **Eine Person** erhält Zugriff auf einen Wert in einer **privaten** Sitzung, die von dieser Person gestartet wurde. Eine Nachricht von jemand anderem hebt die Zuordnung der Sitzung zur Person auf, sodass der Wert nicht mehr verfügbar ist. Geteilte Sitzungen, Trigger, geplante Ausführungen, Webhooks sowie E-Mail- und Telegram-Sitzungen haben keine Person.
- **Ein Agent** erhält in all seinen Sitzungen Zugriff auf einen Wert – auch in Triggern, geplanten Ausführungen und geteilten Sitzungen. Teile einen Wert mit dem Agenten, wenn eine unbeaufsichtigte Ausführung ihn benötigt. Jeder, der diesen Agenten ausführen kann, kann den Wert dann über ihn verwenden. Entscheidend ist also, wer den Agenten ausführen darf (dies wird beim Agenten festgelegt).
- Für serverseitige Nutzer gilt dieselbe Regel. Ein mit dem Secret verknüpfter Connector verwendet es nur für Aufrufer, die zur Zielgruppe gehören. Alle anderen erhalten `credential_not_shared`, und keine Anfrage verlässt Beeuni.
- Beeuni-Dienste, die für niemanden handeln – der Git-Proxy, Webhook-Signaturprüfungen, Channel-Installationen und Beeuni Apps – verwenden nur Werte, die mit allen geteilt wurden.

Mehrere Werte können denselben Namen haben. Ein Wert, der mit der Person der Sitzung geteilt wurde, hat Vorrang vor einem Wert, der mit ihrem Agenten geteilt wurde. Dieser wiederum hat Vorrang vor dem Wert, der mit allen geteilt wurde. Beispiel: `DEEL_API_TOKEN` enthält einen Teamwert, und ein zweiter Wert unter dem Bezeichner `DEEL_API_TOKEN-finance` wird nur mit der Gruppe Finance geteilt. Mitglieder von Finance erhalten in ihren privaten Sitzungen den Finance-Wert; alle anderen und jeder Trigger erhalten den Teamwert.

Eine Person legt die Zielgruppe fest. Eine Agentensitzung kann sie nicht ändern (`403`). Ein Agent kann also einen Wert, der ihm nicht mehr zugänglich ist, weder wieder freigeben noch sich selbst Zugriff gewähren. Personen, die die Secrets des Projekts verwalten, sehen auch Werte, die nicht mit ihnen geteilt wurden. Diese sind als **Nicht mit dir geteilt** gekennzeichnet, damit sie die Freigabe erweitern können.

<a id="sharing-a-session-that-holds-a-personal-value"></a>

### Eine Sitzung teilen, die einen persönlichen Wert enthält

Ein Wert, der nur mit dir geteilt wurde und als **Umgebungsvariable** in deine private Sitzung gelangt ist, liegt in dieser Sandbox im Klartext vor. Wenn du die Sitzung teilst, könnten alle neuen Betrachter ihn lesen. Eine Umgebungsvariable lässt sich außerdem nicht aus einer laufenden Sandbox entfernen. Deshalb verweigert Beeuni das Teilen dieser Sitzung und das Erstellen eines öffentlichen Links dazu, wenn sie `409 PERSONAL_SECRET_REQUIRES_PRIVATE_SESSION` und die darin enthaltenen Namen enthält. Starte eine neue Sitzung zum Teilen oder teile den Wert zuerst mit allen. Werte, die über den Agenten bereitgestellt werden, sowie Egress-geschützte oder serverseitige Werte (die bei jeder Anfrage geprüft werden) verhindern das Teilen nicht.

Wenn du eine Zielgruppe einschränkst, überträgt Beeuni die Änderung erneut an alle laufenden Sandboxes. Ein bereits als Umgebungsvariable bereitgestellter Wert bleibt in einer Sandbox, bis sie neu gestartet wird. Falls er möglicherweise ausgelesen wurde, ändere ihn.

<a id="when-you-enter-a-value-through-a-link"></a>

### Wenn du über einen Link einen Wert eingibst

Ein Agent, der einen Wert benötigt, den du ihm noch nicht gegeben hast, sendet dir einen Link. Auf der Seite kannst du unter **Wer kann es verwenden** auswählen, ob der Wert für alle im Projekt (Standard) oder nur für die Person verfügbar ist, die ihn angefordert hat. Wähle für persönliche Angaben – etwa ein Gehaltsabrechnungs-Token oder einen persönlichen Login – die zweite Option. Auf der Seite wird die anfragende Person nur mit ihrem Anzeigenamen genannt, niemals mit ihrer E-Mail-Adresse, da jeder mit dem Link ihn öffnen kann.

<a id="personal-override"></a>

### Persönlicher Ersatzwert

Ein persönlicher Ersatzwert ist dein eigener Wert für einen Namen. Er ersetzt den geteilten Wert in Sitzungen, die du startest. Derzeit verwendet Beeuni diese Funktion nur für ein OAuth-Login-Zugangstoken. Beeuni lässt niemals zu, dass ein LLM-Anbieterschlüssel, zum Beispiel `ANTHROPIC_API_KEY`, als persönlicher Ersatzwert verwendet wird.

<a id="add-a-secret"></a>

## Ein Secret hinzufügen

### Wert über die CLI festlegen
```bash
beeuni secrets set STRIPE_API_KEY=sk_live_...
```

Beeuni speichert es für alle im Projekt. Füge `--only-me` hinzu, damit es nur für dich verfügbar ist. Um mehrere Werte unter demselben Namen zu speichern, füge `--identifier <id>` hinzu. Namen dürfen nicht mit `BEEUNI_` beginnen – dieses Präfix ist Plattformwerten vorbehalten.

Später ändern, wer es verwenden kann:

```bash
beeuni secrets share DEEL_API_TOKEN --user me
beeuni secrets share DEEL_API_TOKEN --user finance@example.com --group <group-id>
beeuni secrets share NIGHTLY_REPORT_TOKEN --agent reporter
beeuni secrets share DEEL_API_TOKEN --everyone
```

### Oder verwende das Dashboard
Öffne die Secrets-Seite des Projekts, gib Schlüssel und Wert ein, wähle **Wer kann es verwenden** und speichere. Beeuni verschlüsselt den Wert sofort. Für jedes neue Secret gelten standardmäßig **Jeder im Projekt** und die Bereitstellung über die **Umgebung** – der echte Wert wird in die Sandbox geladen. In der Spalte **Wer kann es verwenden** wird angezeigt, für wen der jeweilige Wert verfügbar ist.

Um ein Secret auf eine Bereitstellung mit erzwungenem Egress umzustellen, aktiviere zuerst das `secrets_egress`-Feature-Flag (Settings → Feature flags). Es ist experimentell. Ist das Flag aktiviert, wird auf der Secrets-Seite die Einstellung **„Kann dein Code diesen Wert lesen?“** angezeigt: Mit der Antwort *Nein* wird das Secret auf erzwungenen Egress umgestellt und die Hostliste eingeblendet; mit *Ja* bleibt es bei der Bereitstellung über die Umgebung. Ist das Flag deaktiviert, bleibt das Secret bei der Bereitstellung über die Umgebung.

### Einem Agent gewähren
Wähle auf der Secrets-Seite einen Agent aus oder füge den Bezeichner selbst zur Liste `secrets` des Agents in `beeuni.yaml` hinzu. Eine Sitzung erhält nur die Secrets, für die ihr Agent freigeschaltet ist. Siehe [Einem Agent ein Secret gewähren](#grant-a-secret-to-an-agent).

<a id="grant-a-secret-to-an-agent"></a>

## Einem Agent ein Secret gewähren

Eine Sitzung erhält ein Secret nur, wenn der Agent, mit dem sie ausgeführt wird, den Bezeichner in seiner Liste `secrets` aufführt. Der Abgleich erfolgt anhand des Bezeichners, nicht des Namens, und ignoriert Groß- und Kleinschreibung.

> **Für Secrets mit erzwungenem Egress und für Dienstnutzung ist eine ausdrückliche Freigabe erforderlich**
>
> `secrets: all` gewährt nur die Bereitstellung über die Umgebung. Ein Secret mit erzwungenem Egress sowie jedes Secret, das ein Beeuni-Dienst verwendet, muss ausdrücklich in der Liste eines Agents aufgeführt sein. Ein Projekt ohne `agents:`-Block in `beeuni.yaml` erhält keine Secrets. Nicht freigegebene Secrets werden stillschweigend verworfen: Die Sitzung startet normal, aber der erste Aufruf beim Host schlägt fehl, als wäre die Anmeldeinformation falsch.

<a id="from-the-dashboard"></a>

### Über das Dashboard

Auf der Secrets-Seite ist ein Secret, das keinem Agent zugänglich ist, mit **Kein Agent kann dieses Secret empfangen** gekennzeichnet. Wähle dort einen Agent aus und bestätige. Beeuni bearbeitet `beeuni.yaml` und committet die Änderung als `chore(agents): grant <IDENTIFIER> to <agent>`.

Die Freigabe funktioniert unabhängig davon, ob das Manifest den Agent bereits aufführt. Für einen im Manifest nicht aufgeführten Agent wird ein neuer Eintrag mit dieser einzelnen Liste `secrets` angelegt. Bei einem bereits aufgeführten Agent bleiben alle anderen Felder – Modell, Tools und Konnektoren – erhalten, und der Bezeichner wird seiner bestehenden Liste hinzugefügt. Ist der Bezeichner für einen Agent bereits freigegeben, ist kein Commit erforderlich, und Beeuni erstellt keinen.

Ein Agent auf `secrets: all` ist ein Sonderfall. `all` kann kein Secret mit erzwungenem Egress enthalten. Deshalb schreibt Beeuni eine explizite Liste mit allen derzeit im Projekt vorhandenen Bezeichnern sowie diesem Bezeichner. Was der Agent derzeit erhält, ändert sich dadurch nicht. Ein später hinzugefügtes Secret muss separat freigegeben werden.

In zwei Fällen wird die Freigabe abgelehnt:

- Ein Projekt mit `beeuni_version: 1` (`beeuni.toml`) hat keine Agents-Map, die bearbeitet werden könnte. Die Anfrage schlägt mit `400` und `manifest_v1_unsupported` fehl. Bearbeite das Manifest manuell oder verschiebe das Projekt zu `beeuni_version: 2`.
- Ein Secret mit dem Status **Deaktiviert** kann nicht bereitgestellt werden. Die Anfrage schlägt mit `409` und `secret_not_grantable` fehl. Lege zuerst eine Bereitstellung dafür fest.

Wenn das Projekt noch keinen `agents:`-Block hat, lies vor der Bestätigung [Der erste `agents:`-Block ändert das gesamte Projekt](#the-first-agents-block-changes-the-whole-project).
Diese eine Änderung wirkt sich auf den Zugriff aller anderen Agents auf Secrets aus.

<a id="by-hand"></a>

### Manuell

Dieselbe Freigabe, direkt eingetragen:

```yaml
beeuni_version: 2
agents:
  my-agent:
    secrets: [STRIPE_API_KEY]
```

<a id="when-a-session-asks-for-a-secret-its-agent-is-not-granted"></a>

### Wenn eine Sitzung ein Secret anfordert, für das ihr Agent nicht freigeschaltet ist

Ein Agent, der eine Anmeldeinformation benötigt, erstellt einen Secret-Link (`beeuni secrets request`).
Der eingegebene Wert wird gespeichert, auch wenn der Agent der Sitzung dafür nicht freigeschaltet ist. Diese Sitzung erhält ihn jedoch nie. Beeuni weist daher überall darauf hin:

- Im Formular für den Link steht **Gespeichert, aber `<agent>` kann es noch nicht lesen**; außerdem wird das Secret genannt.
- In der Antwort auf die Erstellung und in der anschließenden Nachricht an die Sitzung werden die Namen der `withheld` mit der Lösung aufgeführt.
- In der Sitzung kennzeichnet `beeuni secrets ls` einen deklarierten Schlüssel außerhalb der Freigabe als `not granted`, nicht als `missing`.

Der Agent kann seine eigene Freigabe nicht erweitern. Öffne **Customize → Agents → `<agent>` → Secrets** und aktiviere das Secret. Beim Speichern überträgt Beeuni die Änderung an die laufenden Sitzungen des Agents. Der Agent kann sie auch sofort mit `beeuni secrets sync` abrufen. Außerdem werden die Secrets einer Sitzung bei jeder Eingabeaufforderung erneut synchronisiert. Ein Neustart ist nicht erforderlich.

<a id="the-first-agents-block-changes-the-whole-project"></a>

### Der erste `agents:`-Block ändert das gesamte Projekt

> **Mit der Deklaration eines Agents werden alle anderen ausgeschlossen**
>
> Ein Projekt ohne `agents:`-Block oder ganz ohne `beeuni.yaml` ist nicht eingeschränkt: Jeder Agent erhält jedes Secret, das über die Umgebung bereitgestellt wird, und kein Agent erhält Secrets mit erzwungenem Egress.
>
> Sobald das Projekt seinen ersten Agent deklariert, erhält jeder **nicht** aufgeführte Agent überhaupt keine Projekt-Secrets mehr – auch keine Secrets aus der Umgebung, die noch vor einer Minute funktioniert haben. Mit der Auflistung eines Agents werden alle anderen ausgeschlossen.

Führe also alle Agents auf, die Secrets benötigen, nicht nur den Agent, den du gerade bearbeitest. Deshalb musst du im Dashboard beim ersten Mal bestätigen: Nach diesem Commit ist `agents:` die Zulassungsliste des Projekts, und Agents, die darin fehlen, laufen ohne Projekt-Secrets.

<a id="exposing-capabilities-to-third-party-users"></a>

## Funktionen für Nutzer von Drittanbietern verfügbar machen

> **Beeuni-Secret-Richtlinien sind kein Autorisierungssystem für mehrere Mandanten**
>
> Eine Secret-Richtlinie schützt den **eigenen Agent deines Projekts** davor, deine Anmeldeinformationen preiszugeben. Sie sagt nichts darüber aus, welche deiner Endnutzer sie verwenden dürfen.

Wenn **nicht vertrauenswürdige Nutzer von Drittanbietern** auf eine Funktion zugreifen – etwa über eine öffentliche Chat-Oberfläche, eine gemeinsam genutzte App oder einen Agent, dem jede Person im Internet Eingabeaufforderungen senden kann –, solltest du ihnen keine Secret-Richtlinien überlassen. Alle Nutzer dieser Oberfläche teilen sich einen Projekt-Agent, eine Freigabe und eine Hostliste. Beeuni kann deine Kunden nicht voneinander unterscheiden. Ein Secret mit erzwungenem Egress, auf das die Eingabeaufforderungen beliebiger Nutzer zugreifen können, ist daher eine Anmeldeinformation, die alle Nutzer bis zum vollen Umfang des Upstream-Schlüssels verwenden können.

Richte die erforderliche Zugriffskontrolle selbst ein:

1. Betreibe einen eigenen Autorisierungs- und Proxydienst. Dieser verwahrt die Upstream-Anmeldeinformation.
2. Richte den Agent auf deinen Dienst statt auf den Upstream aus. Gib dem Agent nur eine Anmeldeinformation für deinen Dienst – diese kann mit erzwungenem Egress auf deinen eigenen Host beschränkt werden.
3. Dein Dienst identifiziert den Endnutzer, wendet deine Autorisierungsregeln und Kontingente pro Nutzer an und ruft erst dann mit der dort verwahrten Anmeldeinformation den Upstream auf.

In diesen Dienst gehören die Regeln pro Nutzer: Wer was wie oft und für welche Datensätze aufrufen darf. Die Secret-Bereitstellung durch Beeuni ist eine darunterliegende Ebene und kein Ersatz dafür.

<a id="list-your-secrets"></a>

## Secrets auflisten

Führe `beeuni secrets ls` aus, um zu sehen, welche Secrets ein Projekt deklariert und für welche ein Wert festgelegt ist.

Die Liste enthält Konfigurationsmetadaten. Sie gibt niemals Secret-Werte zurück. Ein Agent-Token mit eingeschränktem Geltungsbereich sieht nur Bezeichner, die in der Freigabe des Agents enthalten sind. Ein sitzungsspezifisches `secrets_allowlist` steuert die Bereitstellung in dieser Sitzung, verbirgt aber keine Konfigurationsmetadaten, die laut Freigabe des Agents sichtbar sind.

<a id="rotate-a-secret"></a>

## Secret rotieren

### Neuen Wert festlegen
Führe denselben Befehl mit dem neuen Wert aus oder lege ihn erneut auf der Secrets-Seite des Projekts fest:

```bash
beeuni secrets set STRIPE_API_KEY=sk_live_new...
```

### Beeuni überträgt sie an laufende Sitzungen
Beeuni überträgt die Änderung nach bestem Bemühen an jede Sandbox mit einer aktiven Sitzung für das
Projekt. Bei Modell- oder Gateway-Zugangsdaten startet Beeuni den Standard-Harness-Kompatibilitätsprozess neu.

Zum Rotieren eines Egress-erzwungenen Secrets muss der Wert gar nicht übertragen werden: Die
Sandbox hält einen Handle, und Beeuni liest den aktuellen Wert, sobald die nächste
Anfrage eingeht.

<a id="remove-a-secret"></a>

## Secret entfernen

Führe `beeuni secrets unset STRIPE_API_KEY` (oder `unset <identifier>`) aus, oder
lösche es auf der Secrets-Seite des Projekts.

> **Entfernung erfolgt sofort, die Weitergabe nicht**
>
> Beeuni löscht ein gemeinsames Secret sofort. Die Übertragung an bereits laufende
> Sandboxes erfolgt nach bestem Bemühen, genauso wie bei einer Rotation.

<a id="share-a-value-without-seeing-it"></a>

## Einen Wert teilen, ohne ihn zu sehen

Führe `beeuni secrets request STRIPE_API_KEY` aus, um einen Link zu erstellen. Jede Person mit dem
Link kann den Wert eingeben. Du siehst ihn nie. Links sind standardmäßig 7 Tage gültig;
ändere die Dauer mit `--expires <minutes>` (max. 30 Tage). Ein abgelaufener Link zeigt
eine deutliche Seite mit dem Hinweis „abgelaufen“ — erstelle mit demselben Befehl einen neuen.

<a id="give-an-agent-a-value-directly"></a>

## Einem Agenten direkt einen Wert geben

Wenn du in einer Sitzung einen Schlüssel einfügst, speichert der Agent ihn sofort mit
`beeuni secrets set`. Er sendet dir keinen Link. Der
Agent benötigt die Berechtigung zum Schreiben von Secrets im Projekt. Ohne diese Berechtigung erhält der Agent
`403` und erstellt stattdessen einen Secret-Link. Ein Agent kann ein Umgebungs-Secret
oder ein Connector-Secret speichern (`--scope connector`). Erzwingung der Zustellung und Hostlisten
bleiben ausschließlich für Menschen zugänglich.

<a id="end-to-end-example"></a>

## Beispielablauf

`beeuni.yaml`:

```yaml
beeuni_version: 2
default_agent: my-agent
agents:
  my-agent:
    secrets: [STRIPE_API_KEY]
```

Secret-Konfiguration. Der erste Befehl speichert den Wert mit der standardmäßigen
Umgebungsexposition. Der zweite stellt es auf Egress-erzwungene Exposition um. Diese ist experimentell und erfordert das Flag `secrets_egress` (Settings → Feature flags); bei deaktiviertem Flag
wird `403` `feature_disabled` zurückgegeben.

```bash
beeuni secrets set STRIPE_API_KEY=sk_live_...
beeuni secrets delivery STRIPE_API_KEY egress --allow-host api.stripe.com
```

Der Agent ruft Stripe dann mit der ihm übergebenen Variable auf:

```bash
curl -s -o /dev/null -w '%{http_code}\n' \
  -H "authorization: Bearer $STRIPE_API_KEY" \
  https://api.stripe.com/v1/customers
# expected: 200
```

`$STRIPE_API_KEY` enthält einen Handle. Stripe erhält den echten Schlüssel, weil
`api.stripe.com` auf der Liste steht. Dieselbe Anfrage an einen Host, der nicht auf der
Liste steht, sendet den Handle, und der Upstream weist ihn zurück.

Dieselbe Anfrage von einem Agenten, dessen `secrets`-Liste `STRIPE_API_KEY`
nicht enthält, gibt `401` zurück. Die Sitzung wird normal gestartet — ein nicht freigegebenes Secret ist kein
Fehler, es wird einfach nie zugestellt.

<a id="cli-commands"></a>

## CLI-Befehle

| Befehl | Funktion |
|---|---|
| `beeuni secrets ls` | Im Projekt deklarierte und festgelegte Secrets auflisten |
| `beeuni secrets set KEY=VALUE [--identifier <id>] [--scope runtime\|connector]` | Ein Secret erstellen oder aktualisieren. `KEY=-` liest den Wert von stdin. `--scope connector` belässt ihn auf dem Server |
| `beeuni secrets unset IDENTIFIER` | Ein Secret entfernen |
| `beeuni secrets delivery IDENTIFIER egress --allow-host <host>` | Egress-erzwungene Exposition für die aufgeführten Hosts. Experimentell; erfordert das Flag `secrets_egress` |
| `beeuni secrets delivery IDENTIFIER runtime` | Umgebungsexposition (Standard) |
| `beeuni secrets delivery IDENTIFIER denied` | Deaktiviert |
| `beeuni secrets call IDENTIFIER URL` | Eine HTTPS-Anfrage gemäß Richtlinie über Beeuni senden. Experimentell; erfordert das Flag `secrets_egress` |
| `beeuni secrets sync` | In einer Agentensitzung: Secrets für diese Sitzung abrufen und jetzt freigeben. Als Person: erneut an jede aktive Sandbox des Projekts übertragen |
| `beeuni secrets request NAME [--scope runtime\|connector] [--expires <min>]` | Einen Link erstellen, über den eine andere Person einen Wert eingeben kann |
| `beeuni env push --from <path>` | Eine `.env`-Datei als Secrets hochladen |
| `beeuni env pull [--out <path>] [--force]` | Secret-Namen, nicht die Werte, in eine `.env`-Datei exportieren |

Die CLI verwendet die gespeicherten Bezeichnungen: `runtime` steht für Umgebungsexposition,
`egress` für Egress-erzwungen, `denied` für deaktiviert. Führe
`beeuni secrets --help` aus, um alle Flags anzuzeigen.

Setup-Links verwenden standardmäßig `connector`. Verwende `--scope runtime` nur, wenn die Shell des Agenten den Wert erhalten muss. Ein an einen Connector gebundenes Secret bleibt auf dem Server.

<a id="names-and-permissions"></a>

## Namen und Berechtigungen

Formatregeln für die beiden Namen:

| Name | Format |
|---|---|
| `identifier` | `^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$` |
| `name` | `^[A-Z_][A-Z0-9_]{0,63}$` |

Zum Lesen oder Schreiben eines Secrets ist die Berechtigung `project.secret.read` oder
`project.secret.write` erforderlich. Ein Projektmanager hat beide Berechtigungen. Eine benutzerdefinierte Rolle
kann Berechtigungen nur hinzufügen — Beeuni kennt keine Verweigerungsregel — daher kann keine Rolle einem Manager eine der beiden Berechtigungen entziehen. Um die Rechte eines Managers einzuschränken, entferne die Managerrolle.

Die Zustellung an eine Sitzung richtet sich nach der Berechtigungsentscheidung für die Person, die sie gestartet hat,
verknüpft mit der Freigabe im Manifest des gestarteten Agenten. Beide müssen das Secret zulassen. Siehe
[Ein Vokabular, zwei Bindungen](/docs/de/accounts#one-vocabulary-two-bindings).

<a id="rest-routes"></a>

## REST-Routen

Alle Routen liegen unter `/v1/projects/{projectId}`.

| Methode | Pfad | Beschreibung |
|---|---|---|
| GET | `/secrets` | Secrets auflisten. Bei einem eingeschränkten Agententoken auf die Freigaben des Aufrufers beschränkt. |
| POST | `/secrets` | Gemeinsamen Wert erstellen oder aktualisieren. Body: `{name, identifier?, value}`, plus optionale Zustellungsrichtlinie. |
| PUT | `/secrets/{identifier}/strategy` | Exposition und zugehörige Hostliste ändern. |
| POST | `/secrets/{identifier}/grant` | Die Kennung in die `beeuni.yaml`-Liste eines Agenten unter `secrets` aufnehmen. Body: `{agent}`. |
| DELETE | `/secrets/{name}` | Gemeinsamen Wert löschen. Persönliche Überschreibungen bleiben erhalten. |
| PUT | `/secrets/{name}/personal` | Persönliche Überschreibung des Aufrufers festlegen oder aktivieren. |
| DELETE | `/secrets/{name}/personal` | Persönliche Überschreibung des Aufrufers entfernen. |

`POST /secrets` weist Namen zurück, die mit `BEEUNI_` beginnen. Es gibt `409` zurück,
wenn `identifier` bereits mit einem anderen `name` existiert. Den exakten Namen
`CODEX_AUTH_JSON` weist es mit `400` zurück — Beeuni verwaltet dieses Secret
über das ChatGPT-Abonnement-Onboarding.

Beide Schreibrouten geben ein `delivery_sync`-Objekt zurück, wenn die Änderung laufende
Sandboxes erreichen musste. `ok: false` bedeutet, dass der Wert gespeichert wurde, aber mindestens eine aktive
Sitzung noch den vorherigen Wert verwendet; die aufgeführten Sitzungen übernehmen ihn beim Neustart.

Ein Secret in der Liste enthält `delivery_blocked_reason`. Der Wert
`no_agent_grant` bedeutet, dass kein Agent dieses Secret erhalten kann. `null` bedeutet, dass es
freigegeben ist, die Exposition keine Freigabe erfordert oder Beeuni das Manifest nicht lesen konnte.

`POST /secrets/{identifier}/grant` hebt diesen Grund auf. Es gibt
`already_granted: true` zurück, wenn die Liste des Agenten die Kennung bereits zulässt; in diesem
Fall nimmt Beeuni keine Änderung vor. Es gibt `adopted_governance: true` zurück, wenn
die Bearbeitung erstmals einen `agents:`-Block für das Projekt hinzugefügt hat — die oben
beschriebene Änderung](#grant-a-secret-to-an-agent). Bei einem `beeuni.toml`-Projekt lautet die Antwort `400` `manifest_v1_unsupported`,
bei einem deaktivierten Secret `409` `secret_not_grantable`.

<a id="rotation-and-propagation"></a>

## Rotation und Weitergabe

Das Schreiben eines Secrets wartet nicht auf den Neustart einer Sitzung. Beeuni überträgt die
Änderung an jede aktive Sandbox im Projekt:

1. Beeuni erstellt einen neuen Umgebungs-Snapshot unter Verwendung der
   `secrets`-Freigabe des laufenden Agenten.
2. Die Sandbox schreibt den Snapshot in die aktive Agentenumgebung. Neue Tool-Aufrufe
   übernehmen die Änderung sofort.
3. Wenn das geänderte Secret eine Zugangsdaten für einen LLM-Anbieter ist, startet Beeuni
   Standard-Harness neu.

Diese Übertragung erfolgt nach bestem Bemühen. Der API-Aufruf, der das Secret ändert, wird
abgeschlossen, bevor die Übertragung beendet ist. Eine fehlgeschlagene Übertragung wird nur protokolliert und nicht erneut versucht. Eine
Sandbox mit fehlgeschlagener Übertragung behält den alten Wert bis zur nächsten erfolgreichen
Übertragung oder bis zum Neustart der Sitzung.

<a id="model-credentials"></a>

## Modellzugangsdaten

Für ein Projekt mit Beeunis verwaltetem Modellzugriff ist kein eigener Schlüssel erforderlich. Um
deinen eigenen Schlüssel zu verwenden, lege die Anbietervariablen fest, auf die deine Standard-Harness-Anbieterkonfiguration verweist.
Ein erkanntes Modellschlüsselfeld erhält die Verwendung **LLM gateway** und wird serverseitig genutzt; es muss nicht in der Sandbox vorhanden sein.

Verwende ein allgemeines Ergebnis der Anbieterprüfung nicht als Laufzeitnachweis. Es kann
weder das ausgewählte Modell noch Region, Berechtigung und API-Dialekt nachweisen. Sende einen echten
Prompt über genau dieses Modell.
