Zum Inhalt springen

WIF

Kurzlebige Anmeldeinformationen für Claude Code mit Workload Identity Federation

Von Olivares AI 8 min Lesezeit

Sie stellen Claude Code für ein Plattformteam bereit. Sie konfigurieren den Workload-Identitätsverbund von Anthropic so, dass jede Sitzung eine bestätigte OIDC-Assertion gegen ein kurzlebiges Token austauscht. Die Sicherheitsüberprüfung ist sauber: keine statischen Schlüssel, keine Identität pro Sitzung, keine ablaufenden Token. Am nächsten Morgen fügt ein Ingenieur export ANTHROPIC_API_KEY=sk-ant-... zu seinem Shell-Profil hinzu, weil ein Skript es benötigt. Die Föderation wird jetzt für jede vom Techniker ausgeführte Sitzung stillschweigend umgangen. Kein Fehler, keine Warnung, kein Protokolleintrag. Der statische Schlüssel hat Vorrang und der attestierte Pfad wird niemals aufgerufen.

Dies ist keine theoretische Rennbedingung. Dies ist die dokumentierte Auflösungsreihenfolge für Anmeldeinformationen von Anthropic und die häufigste Art und Weise, wie Verbundbereitstellungen stillschweigend fehlschlagen.

Das Problem mit statischen Schlüsseln

Die Standardmethode zur Authentifizierung von Claude Code ist ein statischer API-Schlüssel: eine sk-ant--Zeichenfolge, die als ANTHROPIC_API_KEY festgelegt ist. Es funktioniert und verfügt über drei Eigenschaften, die im Widerspruch zur Unternehmensidentitätsverwaltung stehen.

Kein Ablauf, kein Rotationssignal. Ein statischer Schlüssel ist gültig, bis ihn jemand widerruft. Es gibt keine integrierte Lebensdauer, keine Rotationserinnerung und keinen Mechanismus, der eine erneute Authentifizierung erzwingt. Ein während eines Proof-of-Concept ausgegebener Schlüssel kann noch Monate später Produktions-Workloads authentifizieren.

Gemeinsame Identität. Jede Sitzung, die denselben Schlüssel verwendet, authentifiziert sich als derselbe Prinzipal. Der Prüfpfad zeigt, welcher Arbeitsbereich verwendet wurde, kann jedoch nicht unterscheiden, welcher Techniker, welche Maschine oder welche Automatisierung eine bestimmte Anforderung ausgeführt hat. Eine Zuordnung pro Sitzung ist strukturell unmöglich.

Stiller Vorrang vor der Föderation. Das ist die Fußfeuerwaffe. Die Anmeldeinformationsauflösung von Anthropic platziert den statischen Schlüssel (ANTHROPIC_API_KEY, Ebene 2) über dem Verbundpfad (Ebene 4). Wenn beide in derselben Umgebung vorhanden sind, gewinnt der statische Schlüssel. Der Föderationsaustausch wird nie versucht. Es wird kein Fehler ausgelöst. Die Arbeitslast wird erfolgreich unter der Identität des statischen Schlüssels ausgeführt, und alle auf der Föderation basierenden Governance-Annahmen – sitzungsbezogene Identität, bestätigte Behauptungen, Token-Ablauf – werden stillschweigend ungültig.

Sogar eine leere Variable (ANTHROPIC_API_KEY="") belegt ihren Prioritätsplatz. Die Authentifizierung schlägt zwar fehl, verhindert jedoch weiterhin, dass die Laufzeit den Verbundpfad erreicht. Der Fehlermodus ist „Authentifizierungsfehler“ und nicht „Falling through to Federation“.

Funktionsweise der Workload-Identitätsföderation

WIF ersetzt den statischen Schlüssel durch einen Austausch: Eine verifizierte Behauptung geht ein, ein kurzlebiges Token kommt heraus. Die Behauptung ist ein JWT – entweder eine JWT-SVID von einem SPIFFE-Identitätsanbieter oder ein Standard-OIDC-Token von einem beliebigen Aussteller, dem die Anthropic-Organisation vertraut.

Der Austausch folgt RFC 7523 (JWT Inhaberzuteilung). Der Workload präsentiert seine Behauptung dem Token-Endpunkt von Anthropic zusammen mit drei Kennungen: welche Föderationsregel abgeglichen werden soll (fdrl_), welches Dienstkonto als agieren soll (svac_) und zu welcher Organisation der Austausch gehört. Im Code ist der Kern des Austauschs ein POST mit einem JSON-Body:

type exchangeRequest struct {
    GrantType        string `json:"grant_type"`         // "urn:ietf:params:oauth:grant-type:jwt-bearer"
    Assertion        string `json:"assertion"`          // der verifizierte JWT-SVID- oder OIDC-Token
    FederationRuleID string `json:"federation_rule_id"` // fdrl_...
    OrganizationID   string `json:"organization_id"`
    ServiceAccountID string `json:"service_account_id"` // svac_...
    WorkspaceID      string `json:"workspace_id,omitempty"`
}

Die Antwort ist eine RFC 6749-Token-Antwort. Das geprägte Token trägt das Präfix sk-ant-oat (OAT = OAuth Access Token), einen deklarierten Bereich (workspace:developer für vollständigen nicht-administrativen API-Zugriff oder org:manage_tunnels für MCP-Tunnelverwaltung) und eine Lebensdauer zwischen 60 Sekunden und 24 Stunden.

Es gibt kein Aktualisierungstoken. Wenn das geprägte Token abläuft, muss die Arbeitslast ihre Behauptung erneut präsentieren und den Austausch erneut ausführen. Dies ist beabsichtigt: Die Behauptung selbst wird attestiert (vorgelagert durch die SPIFFE-Workload-API oder den OIDC-Anbieter überprüft), sodass jeder erneute Austausch eine erneute Attestierung darstellt. Ein kompromittiertes Token ist nur für seine verbleibende Lebensdauer nützlich und es gibt keinen Aktualisierungspfad, den ein Angreifer ausnutzen kann, um es zu verlängern.

Das Ergebnis ist eine Identität pro Sitzung. Jede Claude Code-Sitzung tauscht ihre eigene Behauptung aus, erhält ihr eigenes kurzlebiges Token und authentifiziert sich als eindeutiger Prinzipal. Der Audit-Trail zeichnet auf, welches Dienstkonto agiert hat, an welche Verbundregel gebunden ist und auf welchen Arbeitsbereich beschränkt ist.

Erkennen der Footgun „Static-Key-Shadows-Federation“.

Die Bereitstellung von WIF reicht nicht aus. Sie müssen auch erkennen, wenn etwas in der Umgebung es stillschweigend umgeht. Der Connector überprüft die Laufzeitumgebung auf das Vorhandensein statischer Anmeldeinformationen (ANTHROPIC_API_KEY oder ANTHROPIC_AUTH_TOKEN) und prüft, ob gleichzeitig eine Föderation verwendet wird (entweder durch deklarierte Föderationsregeln oder durch das Signal ANTHROPIC_IDENTITY_TOKEN_FILE). Wenn beide Bedingungen zutreffen, wird ein Governance-Ergebnis mit hohem Schweregrad ausgegeben.

func (s *Source) detectShadowing(at time.Time) (model.FindingReport, bool) {
    _, hasKey := s.envLookup(envAPIKey)
    _, hasAuth := s.envLookup(envAuthToken)
    if !hasKey && !hasAuth {
        return model.FindingReport{}, false
    }
    _, hasTokenFile := s.envLookup(envIdentityTokenFile)
    federationInUse := len(s.federation) > 0 || hasTokenFile
    if !federationInUse {
        return model.FindingReport{}, false
    }
    // ...
    return model.FindingReport{
        Kind:     "governance",
        Severity: model.SeverityHigh,
        Title:    "Static Anthropic key shadows Workload Identity Federation",
        // DetailHash identifiziert, WELCHE Variable Vorrang hat — niemals den Wert
    }, true
}

Der Detail-Hash des Ergebnisses zeichnet auf, welche statische Variable vorhanden ist und welches Verbundsignal sie verschattet, ohne jemals den Wert des Schlüssels einzubetten. Nicht einmal eine maskierte Form. Der Hash ist über alle Läufe hinweg stabil, sodass die Governance-Engine ihn dedupliziert und ein SIEM ihn fallweise abfragen kann.

Ein statischer Schlüssel ohne verwendeten Verbund ist nur ein statischer Schlüssel – der Connector kennzeichnet ihn nicht. Das Ergebnis wird nur ausgelöst, wenn beide vorhanden sind, da dies die spezifische Konfiguration ist, bei der der Operator davon ausgeht, dass die Föderation aktiv ist, dies jedoch nicht der Fall ist.

Die Versöhnungsschleife: deklariert vs. tatsächlich

Das Erkennen der Fußfeuerwaffe mit statischer Taste ist schon die halbe Miete. Die andere Hälfte überprüft, ob die Föderationskonfiguration selbst nicht abgewichen ist. Der Connector verwaltet eine deklarierte Baseline – die Föderationsregeln, die der Operator explizit als geregelt deklariert – und vergleicht sie mit dem Live-Status der WIF-Konfiguration der Organisation Anthropic.

Der Live-Status kommt von drei WIF Admin API-Endpunkten:

  • GET /v1/organizations/service_accounts – die Dienstkonten (svac_), auf die Föderationsregeln abzielen
  • GET /v1/organizations/federation_issuers – die OIDC/SPIFFE-Aussteller (fdis_), denen die Organisation vertraut
  • GET /v1/organizations/federation_rules – die Regeln (fdrl_), die Aussteller an Dienstkonten binden

Diese Endpunkte erfordern ein org:admin OAuth-Bearer-Token – eine andere Anmeldeinformation als der sk-ant-admin-Administrator-API-Schlüssel, den der Roster liest. Die Admin-API WIF lehnt Admin-API-Schlüssel ausdrücklich ab, weshalb der Connector einen separaten authentifizierten Client für den Abgleich verwendet.

Der Unterschied zwischen deklariert und live führt zu sieben Ergebniskategorien:

DriftkofferWas es bedeutetSchweregrad
undeclared_live_ruleEine Live-Regel, die der Betreiber nie erklärt hat oder regeltHoch
declared_rule_not_liveEine deklarierte Regel, die stromaufwärts nicht mehr existiertMittel
scope_driftDer Live-Bereich weicht vom deklarierten Bereich abMittel (Hoch, wenn es auf die gesamte Organisation ausgeweitet wird)
lifetime_driftDie Lebensdauer des Live-Tokens weicht von der angegebenen abMittel (Hoch, wenn länger als angegeben)
over_broad_subjectEine Live-Regel ohne echte SubjektbeschränkungMittel
orphan_ruleEine Regel, die auf einen fehlenden Aussteller oder ein fehlendes Dienstkonto verweistMittel
orphan_issuerEin Emittent, auf den keine Regel verweistNiedrig

Zwei Fälle eskalieren automatisch zu einem hohen Schweregrad: ein Live-Bereich, der auf einen organisationsweiten oder Admin-Bereich erweitert wurde, den der Betreiber nicht deklariert hat, und eine Live-Token-Lebensdauer, die länger als die geregelte Basislinie ist. Beides erweitert den Explosionsradius über den vom Bediener genehmigten Bereich hinaus. Die Bereichsnormalisierung (Trimmen, Deduplizieren, Sortieren) verhindert Fehlalarme durch Leerzeichen oder Sortierunterschiede.

Wenn kein org:admin-Token konfiguriert ist, wird der Abgleichsdurchlauf einfach nicht ausgeführt. Der Connector arbeitet nur mit der deklarierten Basislinie und ist ehrlich in Bezug auf seine Abdeckung: Er erstellt niemals einen Live-Dienstplan. Wenn die Live-API nicht erreichbar ist (Netzwerkfehler, Token-Ablauf), gibt sie ein einzelnes reconciliation_unavailable-Ergebnis aus und fährt fort – die Dienstplangewährungen und die Footgun-Erkennung dürfen nicht an den Zustand des org:admin-Tokens gekoppelt sein.

Zuerst lesen und minimale Daten

Der Connector folgt einem strikten Datenminimierungsvertrag. Jeder API-Aufruf ist ein GET. Es erstellt, aktualisiert oder löscht niemals ein Anthropic-Objekt. Es enthält nur Identitätsmetadaten: IDs, Namen, E-Mails, Rollen, wichtige Hinweise. Niemals ein Schlüsselgeheimnis. Niemals ein privater Schlüssel. Niemals ein geprägter Token im Ruhezustand.

Das vom WIF-Austausch geprägte Token wird an den Aufrufer zurückgegeben und vom Konnektor niemals protokolliert, beibehalten oder ausgegeben. Der einzige Datensatz, der das Governance-Ledger erreicht, ist die Struktur ExchangeAudit – die bewusst kein Token trägt:

type ExchangeAudit struct {
    FederationRuleID string
    OrganizationID   string
    ServiceAccountID string
    WorkspaceID      string
    Scope            string
    TokenType        string
    ExpiresAt        time.Time
}

Die gleiche Minimierung gilt für die Live-Abstimmung. Wenn der Connector die JWKS-Konfiguration eines Verbundausstellers liest, reduziert er die Antwort auf zwei boolesche Werte: den Erkennungsmodus (discovery, explicit_url oder inline) und ob ein benutzerdefiniertes CA-Zertifikat angeheftet ist. Das Inline-JWK-Material – öffentliche Schlüssel, die jedoch umfangreich sind und nie für Governance-Entscheidungen benötigt werden – wird niemals in ein gespeichertes oder ausgegebenes Feld dekodiert. Das CA-Zertifikat PEM wird nur dekodiert, um ein Anwesenheitsflag abzuleiten, und wird sofort verworfen.

CEL-Bedingungen für Verbundregeln werden für die Statusanalyse übernommen (der CEL-Ausdruck einer Regel ist Teil ihrer Sicherheitsgrenze), werden jedoch nie ausgewertet. Der Connector ist nicht von der CEL-Engine abhängig – die Evaluierung ist ein separates Anliegen.

Was dies ermöglicht

Statische Schlüssel verbinden Authentifizierung mit Identität. Jede Sitzung ist derselbe Principal, jedes Token bleibt für immer bestehen, und das Vorhandensein eines Schlüssels in einer Punktdatei deaktiviert stillschweigend jede Föderation, von der Sie dachten, sie würde Sie schützen.

WIF trennt die beiden. Die Authentifizierung erfolgt durch eine beglaubigte Behauptung, die beweist, dass es sich bei der Arbeitslast um die Person handelt, für die sie sich ausgibt. Die Identität ist auf die Sitzung beschränkt: ein kurzlebiges Token, ein bestimmtes Dienstkonto, ein bestimmter Arbeitsbereich, ein deklarierter Bereich. Wenn das Token abläuft, wird die Arbeitslast erneut bestätigt. Wenn die Konfiguration abweicht, deckt die Abstimmungsschleife die Lücke auf. Wenn ein statischer Schlüssel den gesamten Mechanismus überschattet, wird er vom Konnektor erkannt und gemeldet, bevor er zu einem Vorfall wird.

Das Ergebnis ist ein Identitätsmodell, bei dem Anmeldeinformationen ablaufen, Sitzungen zuordenbar sind und Governance-Annahmen kontinuierlich anhand des tatsächlichen Zustands der Organisation überprüft werden – nicht nur des Zustands, den jemand beabsichtigt hat.


Der Identitätskonnektor, der WIF-Austausch und die Footgun-Erkennung sind Teil des Identity Governance-Moduls. Informationen zum umfassenderen Sicherheitsmodell – dem Ledger, der Access Map, der Read-First-Collection-Architektur – finden Sie unter Sicherheit.

Verwandte Beiträge

Häufige Fragen

Muss der statische Schlüssel einen gültigen API-Schlüssel für die Schattenföderation enthalten?

Nein. Der Vorrang der Anmeldeinformationen von Anthropic basiert auf der Anwesenheit, nicht auf der Gültigkeit. Ein leerer ANTHROPIC_API_KEY="" gewinnt seinen Prioritätsplatz genau wie ein gefüllter Schlüssel: Er befindet sich in der Auflösungsreihenfolge über den Föderationsebenen, sodass die Laufzeit niemals auf den attestierten Pfad durchfällt. Der Connector erkennt dies, indem er prüft, ob die Umgebungsvariable gesetzt ist (os.LookupEnv) und nicht, ob ihr Wert nicht leer ist. Bei einem leeren Schlüssel schlägt die Authentifizierung fehl, die Föderation wird jedoch genauso gründlich abgeschirmt wie bei einem echten.

Was passiert, wenn ich kein org:admin OAuth-Token für die Live-Abstimmung habe?

Der Stecker funktioniert auch ohne. Es modelliert genau das, was der Operator in der Föderationskonfiguration deklariert, gibt den verwalteten NHI-Dienstplan und die zulässigen Gewährungskanten aus diesen Deklarationen aus und führt die Footgun-Erkennung mit statischen Schlüsseln aus. Der Live-Abstimmungsdurchgang wird einfach übersprungen, da die Admin-API-Endpunkte WIF alles andere als ein org:admin OAuth-Bearer-Token ablehnen. Sie erhalten eine nur deklarierte Basislinie, die in Bezug auf die Berichterstattung ehrlich ist: Es wird niemals ein Live-Dienstplan erstellt.

Sehen Sie, worauf Ihre Agenten zugreifen können

Olivares AI ist die offene, selbstgehostete Plattform für Ihre KI-Landschaft. Betreiben Sie sie auf Ihrer eigenen Infrastruktur und erhalten Sie die Zugriffskarte, nach der Ihre Security- und Platform-Teams seit Langem fragen.