Przejdź do treści

Tłumaczenie maszynowe. Wersja angielska jest wiążąca; weryfikacja przez native speakera jeszcze nie nastąpiła.

WIF

Tymczasowe poświadczenia dla Claude Code z federacją tożsamości obciążenia

Autor Olivares AI 8 min do przeczytania

Używasz Claude Code dla zespołu platformy. Konfigurujesz federację tożsamości obciążenia Anthropic, tak aby każda sesja wymieniała poświadczone stwierdzenie OIDC na krótkożyjącą token. Przegląd bezpieczeństwa jest czysty: brak kluczy statycznych, tożsamość przypisana do sesji, tokeny, które wygasają. Następnego ranka jeden z inżynierów dodaje export ANTHROPIC_API_KEY=sk-ant-... do swojego profilu shell, ponieważ skrypt go potrzebuje. Federacja jest teraz cicho omijana dla każdej sesji uruchamianej przez tego inżyniera. Brak błędu, brak ostrzeżenia, brak wpisu w logu. Klucz statyczny ma pierwszeństwo i ścieżka poświadczona nigdy nie jest uruchamiana.

To nie jest teoretyczny stan wyścigu. Jest to udokumentowany porządek rozwiązywania poświadczeń Anthropic i jest to najczęstszy sposób, w jaki wdrożenia federacyjne cicho zawodzą.

Problem z kluczami statycznymi

Domyślny sposób uwierzytelniania Claude Code to statyczny klucz API: ciąg sk-ant- ustawiony jako ANTHROPIC_API_KEY. Działa to i ma trzy cechy, które stoją w konflikcie z zarządzaniem tożsamością w przedsiębiorstwie.

Brak wygaśnięcia, brak sygnału rotacji. Statyczny klucz jest ważny do momentu, gdy ktoś go unieważni. Nie ma wbudowanego okresu ważności, przypomnienia o rotacji ani mechanizmu wymuszającego ponowne uwierzytelnienie. Klucz wydany podczas proof-of-concept może nadal uwierzytelniać obciążenia produkcyjne miesiące później.

Wspólna tożsamość. Każda sesja używająca tego samego klucza uwierzytelnia się jako ten sam podmiot. Ślad audytu pokazuje, które środowisko pracy było używane, ale nie może rozróżnić, który inżynier, która maszyna lub która automatyzacja wykonała konkretne żądanie. Przypisanie do sesji jest strukturalnie niemożliwe.

Cicha przewaga nad federacją. To jest pułapka własna. Rozwiązywanie poświadczeń Anthropic umieszcza statyczny klucz (ANTHROPIC_API_KEY, poziom 2) ponad ścieżką federacji (poziom 4). Gdy oba istnieją w tym samym środowisku, zwycięża klucz statyczny. Wymiana federacyjna nigdy nie jest próbowana. Nie występuje żaden błąd. Obciążenie działa pomyślnie pod tożsamością klucza statycznego, a wszystkie założenia dotyczące zarządzania oparte na federacji — tożsamość ograniczona do sesji, poświadczone stwierdzenia, wygaśnięcie tokenu — są cicho unieważniane.

Nawet pusty zmienny (ANTHROPIC_API_KEY="") zajmuje swoje miejsce w kolejności priorytetów. Uwierzytelnianie nie powiedzie się, ale wciąż uniemożliwi środowisku uruchomieniowemu dotarcie do ścieżki federacji. Tryb błędu to „błąd uwierzytelniania”, a nie „przejście do federacji”.

Jak działa federacja tożsamości obciążenia

WIF zastępuje statyczny klucz wymianą: wchodzi zweryfikowane oświadczenie, wychodzi krótko żyjący token. Oświadczenie jest JWT — albo JWT-SVID od dostawcy tożsamości SPIFFE, albo standardowy token OIDC od dowolnego wydawcy, któremu ufa organizacja Anthropic.

Wymiana odbywa się zgodnie z RFC 7523 (JWT przyznanie typu bearer). Obciążenie prezentuje swoje oświadczenie do punktu końcowego tokenu Anthropic wraz z trzema identyfikatorami: która zasada federacji powinna być dopasowana (fdrl_), jako które konto serwisowe ma działać (svac_) oraz do której organizacji należy wymiana. W kodzie, sedno wymiany to żądanie POST z ciałem w formacie JSON:

type exchangeRequest struct {
    GrantType        string `json:"grant_type"`         // "urn:ietf:params:oauth:grant-type:jwt-bearer"
    Assertion        string `json:"assertion"`          // zweryfikowany JWT-SVID lub token OIDC
    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"`
}

Odpowiedź jest odpowiedzią tokenową RFC 6749. Wydany token posiada prefiks sk-ant-oat (OAT = OAuth Token Dostępu), zadeklarowany zakres (workspace:developer dla pełnego nieadministracyjnego dostępu do API, lub org:manage_tunnels dla MCP zarządzania tunelem) oraz czas życia między 60 sekundami a 24 godzinami.

Nie ma tokenu odświeżającego. Po wygaśnięciu wydanego tokenu, obciążenie musi ponownie przedstawić swoje poświadczenie i wykonać ponownie wymianę. Jest to celowe: samo poświadczenie jest poświadczone (zweryfikowane przez SPIFFE workload API lub dostawcę OIDC), dlatego każda ponowna wymiana to ponowne poświadczenie. Skompromitowany token jest użyteczny tylko przez pozostały czas życia i nie istnieje ścieżka odświeżania, którą atakujący mógłby wykorzystać do jego przedłużenia.

Wynikiem jest tożsamość per-sesję. Każda sesja Claude Code wymienia własne stwierdzenie, otrzymuje własny, krótkotrwały token i uwierzytelnia się jako odrębny podmiot. Rejestr audytu zapisuje, które konto usługowe działało, powiązane z którą regułą federacji, ograniczoną do którego obszaru roboczego.

Wykrywanie pułapki static-key-shadows-federation

Samo wdrożenie WIF nie wystarczy. Musisz również wykryć, kiedy coś w środowisku cicho je omija. Konektor sprawdza środowisko wykonawcze pod kątem obecności statycznego poświadczenia (ANTHROPIC_API_KEY lub ANTHROPIC_AUTH_TOKEN) i weryfikuje, czy federacja jest używana jednocześnie (albo poprzez zadeklarowane reguły federacji, albo poprzez sygnał ANTHROPIC_IDENTITY_TOKEN_FILE). Gdy oba warunki są spełnione, generuje zgłoszenie o wysokim stopniu istotności w zakresie zarządzania.

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 identyfikuje, KTÓRA zmienna ma pierwszeństwo — nigdy jej wartość
    }, true
}

Szczegółowy skrót znalezienia rejestruje która zmienna statyczna jest obecna i który sygnał federacji zasłania, nigdy nie osadzając wartości klucza. Nawet w formie maskowanej. Skrót jest stabilny między uruchomieniami, więc silnik zarządzający go deduplikuje, a SIEM może go wyszukiwać według sprawy.

Statyczny klucz bez używanej federacji jest po prostu statycznym kluczem — łącznik go nie oznacza. Znalezienie aktywuje się tylko wtedy, gdy obu istnieją, ponieważ to jest konkretna konfiguracja, w której operator uważa, że federacja jest aktywna, podczas gdy tak nie jest.

Pętla uzgadniania: zadeklarowane vs. faktyczne

Wykrycie problemu z kluczem statycznym to połowa obrazu. Druga połowa to weryfikacja, czy sama konfiguracja federacji nie uległa dryfowi. Connector utrzymuje zadeklarowaną bazową konfigurację — zasady federacji, które operator wyraźnie deklaruje jako obowiązujące — i porównuje ją ze stanem rzeczywistym konfiguracji WIF organizacji Anthropic.

Stan rzeczywisty pochodzi z trzech punktów końcowych WIF Admin API:

  • GET /v1/organizations/service_accounts — konta usług (svac_), do których odnoszą się zasady federacji
  • GET /v1/organizations/federation_issuers — wystawcy OIDC/SPIFFE (fdis_), którym organizacja ufa
  • GET /v1/organizations/federation_rules — zasady (fdrl_), które wiążą wystawców z kontami usług

Te punkty końcowe wymagają tokena nosiciela org:admin OAuth — odrębnego poświadczenia od klucza Admin API sk-ant-admin, który jest używany przez listę uczestników. Admin API WIF jawnie odrzuca klucze Admin API, dlatego łącznik używa osobnego uwierzytelnionego klienta do rekonsyliacji.

Różnica między zadeklarowanym a rzeczywistym tworzy siedem kategorii wyników:

Przypadek odchyleniaCo to oznaczaWaga
undeclared_live_ruleRzeczywista zasada, której operator nigdy nie zadeklarował lub nie nadzorujeWysoka
declared_rule_not_liveZadeklarowana zasada, która już nie istnieje w górzeŚrednia
scope_driftAktywny zakres różni się od zadeklarowanego zakresuŚredni (Wysoki, jeśli rozszerzony na całą organizację)
lifetime_driftCzas życia aktywnego tokena różni się od zadeklarowanegoŚredni (Wysoki, jeśli dłuższy niż zadeklarowany)
over_broad_subjectAktywna reguła bez rzeczywistego ograniczenia podmiotuŚredni
orphan_ruleReguła odwołująca się do brakującego wydawcy lub konta serwisowegoŚredni
orphan_issuerWydawca, do którego nie odnosi się żadna regułaNiski

Dwie sprawy eskalują do wysokiej wagi automatycznie: aktywny zakres, który rozszerzył się do całej organizacji lub zakresu administracyjnego, którego operator nie zadeklarował, oraz okres życia aktywnego tokena, który jest dłuższy niż ustanowiony standard. Oba zwiększają promień wpływu poza to, na co zgodził się operator. Normalizacja zakresu (przycinanie, usuwanie duplikatów, sortowanie) zapobiega fałszywym trafieniom wynikającym z różnic w białych znakach lub kolejności.

Kiedy żaden token org:admin nie jest skonfigurowany, proces uzgadniania po prostu się nie uruchamia. Connector działa tylko z deklarowanym standardem bazowym i jest uczciwy co do swojego pokrycia: nigdy nie tworzy fałszywego aktywnego wykazu. Gdy nie można uzyskać dostępu do aktywnego API (błąd sieci, wygaśnięcie tokena), generuje pojedyncze znalezienie reconciliation_unavailable i kontynuuje – uprawnienia wykazu i wykrywanie zagrożeń nie powinny być powiązane ze stanem tokena org:admin.

Czytaj-pierwsze i minimalne dane

Konektor przestrzega ścisłej umowy dotyczącej minimalizacji danych. Każde wywołanie API jest typu GET. Nigdy nie tworzy, nie aktualizuje ani nie usuwa obiektu Anthropic. Przenosi wyłącznie metadane tożsamości: identyfikatory, imiona, adresy e-mail, role, wskazówki dotyczące kluczy. Nigdy sekretu klucza. Nigdy klucza prywatnego. Nigdy wybitego tokena w stanie spoczynku.

Wybijany token z wymiany WIF jest zwracany wywołującemu i nigdy nie jest logowany, przechowywany ani emitowany przez konektor. Jedynym zapisem, który trafia do rejestru zarządzania, jest struktura ExchangeAudit — która celowo nie zawiera żadnego tokena:

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

Ta sama minimalizacja dotyczy synchronizacji na żywo. Gdy konektor odczytuje konfigurację JWKS wydawcy federacji, redukuje odpowiedź do dwóch wartości logicznych: trybu odkrywania (discovery, explicit_url lub inline) oraz czy jest przypięty niestandardowy certyfikat CA. Materiał JWK w linii — klucze publiczne, ale obszerne i nigdy niepotrzebne do decyzji rządzenia — nigdy nie jest dekodowany do przechowywanego lub emitowanego pola. Certyfikat CA w formacie PEM jest dekodowany tylko po to, aby uzyskać flagę obecności i jest natychmiast odrzucany.

Warunki CEL dotyczące zasad federacji są uwzględniane w analizie postawy (wyrażenie CEL reguły jest częścią jej granicy bezpieczeństwa), ale nigdy nie są oceniane. Konektor nie ma zależności od silnika CEL — ocena to osobna kwestia.

Co to umożliwia

Statyczne klucze mieszają uwierzytelnianie z tożsamością. Każda sesja jest tym samym podmiotem, każdy token żyje wiecznie, a obecność klucza w pliku konfiguracyjnym cicho wyłącza jakąkolwiek federację, która miała cię chronić.

WIF rozdziela te dwa elementy. Uwierzytelnianie odbywa się poprzez poświadczone stwierdzenie, które udowadnia, że obciążenie robocze jest tym, za kogo się podaje. Tożsamość jest ograniczona do sesji: token o krótkim czasie życia, określone konto usługi, konkretna przestrzeń robocza, zadeklarowany zakres. Gdy token wygaśnie, obciążenie robocze ponownie się poświadcza. Gdy konfiguracja odbiega od normy, pętla uzgadniania ujawnia gap. Gdy statyczny klucz zasłania cały mechanizm, łącznik wykrywa go i raportuje, zanim stanie się to zagadnieniem incydentowym.

Wynikiem jest model tożsamości, w którym poświadczenia wygasają, sesje są przypisywalne, a założenia dotyczące zarządzania są ciągle weryfikowane w stosunku do rzeczywistego stanu organizacji — a nie tylko stanu, jaki ktoś przewidywał.


Connector tożsamości, wymiana WIF oraz wykrywanie błędnych działań są częścią modułu zarządzania tożsamościami. Dla szerszego modelu bezpieczeństwa — rejestru, mapy dostępu, architektury kolekcji read-first — zobacz bezpieczeństwo.

Powiązane artykuły

Najczęstsze pytania

Czy statyczny klucz musi zawierać ważny klucz API, aby zastąpić federację?

Nie. Uprzedniość poświadczeń Anthropic opiera się na obecności, a nie na ważności. Pusty ANTHROPIC_API_KEY="" zajmuje swoje miejsce w uprzedniości tak samo jak wypełniony klucz: znajduje się ponad poziomami federacji w kolejności rozwiązywania, więc środowisko wykonawcze nigdy nie przechodzi do ścieżki poświadczonej. Konfigurator wykrywa to, sprawdzając, czy zmienna środowiskowa jest ustawiona (os.LookupEnv), a nie czy jej wartość jest niepusta. Pusty klucz zakończy się niepowodzeniem uwierzytelnienia, ale będzie zacieniał federację równie skutecznie jak prawdziwy.

Co się stanie, jeśli nie będę miał tokenu org:admin OAuth do bieżącej rekonsyliacji?

Łącznik działa bez niego. Modeluje dokładnie to, co operator deklaruje w konfiguracji federacji, emituje zarządzany zestaw NHI oraz dozwolone krawędzie przyznania z tych deklaracji i uruchamia wykrywanie pułapek związanych ze statycznym kluczem. Po prostu pomija etap weryfikacji na żywo, ponieważ punkty końcowe WIF Admin API odrzucają wszystko inne niż token nosiciela org:admin OAuth. Otrzymujesz jedynie bazę deklarowaną, która jest szczera co do swojego pokrycia: nigdy nie fabrykuje listy na żywo.

Sprawdź dostęp Twoich agentów

Olivares AI to otwarta platforma w modelu hostowanym samodzielnie dla całego środowiska AI w organizacji. Wdrożenie na własnej infrastrukturze zapewnia mapę dostępu, o którą od dawna proszą zespoły bezpieczeństwa i platformowe.