본문으로 건너뛰기

기계 번역입니다. 정식 기준은 영어판이며, 원어민 검수는 아직 완료되지 않았습니다.

WIF

워크로드 아이덴티티 페더레이션이 포함된 Claude Code에 대한 임시 자격 증명

작성자 Olivares AI 6 분 소요

플랫폼 팀을 위해 Claude Code를 배포합니다. 모든 세션이 단기 토큰에 대해 증명된 OIDC 어설션을 교환하도록 Anthropic의 워크로드 아이덴티티 페더레이션을 구성합니다. 보안 검토는 깨끗합니다. 정적 키, 세션별 ID, 만료되는 토큰이 없습니다. 다음날 아침 한 엔지니어는 스크립트에 필요하기 때문에 export ANTHROPIC_API_KEY=sk-ant-...를 쉘 프로필에 추가했습니다. 이제 엔지니어가 실행하는 모든 세션에 대해 페더레이션이 자동으로 우회됩니다. 오류, 경고, 로그 항목이 없습니다. 정적 키가 우선적으로 적용되며 증명된 경로는 호출되지 않습니다.

이것은 이론적인 경쟁 조건이 아닙니다. 이는 Anthropic의 문서화된 자격 증명 확인 순서이며 페더레이션 배포가 조용히 실패하는 가장 일반적인 방법입니다.

정적 키 문제

Claude Code를 인증하는 기본 방법은 정적 API 키, 즉 ANTHROPIC_API_KEY로 설정된 sk-ant- 문자열입니다. 작동하며 기업 ID 관리와 충돌하는 세 가지 속성이 있습니다.

만료 없음, 회전 신호 없음. 정적 키는 누군가가 취소할 때까지 유효합니다. 기본 제공 수명, 순환 알림, 재인증을 강제하는 메커니즘이 없습니다. 개념 증명 중에 발급된 키는 몇 달 후에도 계속 프로덕션 워크로드를 인증할 수 있습니다.

공유 ID. 동일한 키를 사용하는 모든 세션은 동일한 주체로 인증됩니다. 감사 추적에는 어떤 작업 공간이 사용되었는지 표시되지만 어떤 엔지니어, 어떤 기계 또는 어떤 자동화가 특정 요청을 실행했는지 구분할 수 없습니다. 세션별 ​​어트리뷰션은 구조적으로 불가능합니다.

연맹보다 조용한 우선권. 이것이 바로 풋건입니다. Anthropic의 자격 증명 확인은 페더레이션 경로(계층 4) 위에 정적 키(ANTHROPIC_API_KEY, 계층 2)를 배치합니다. 둘 다 동일한 환경에 존재하면 정적 키가 우선합니다. 페더레이션 교환은 시도되지 않습니다. 오류가 발생하지 않습니다. 워크로드는 정적 키의 ID로 성공적으로 실행되며 페더레이션에 구축된 모든 거버넌스 가정(세션 범위 ID, 증명된 어설션, 토큰 만료)이 자동으로 무효화됩니다.

빈 변수(ANTHROPIC_API_KEY="")도 우선순위 슬롯을 차지합니다. 인증은 실패하지만 여전히 런타임이 페더레이션 경로에 도달하지 못하게 됩니다. 실패 모드는 “페더레이션 통과”가 아닌 “인증 오류”입니다.

워크로드 아이덴티티 제휴 작동 방식

WIF는 정적 키를 교환으로 대체합니다. 검증된 어설션이 들어가고 단기 토큰이 나옵니다. 어설션은 JWT(SPIFFE ID 공급자의 JWT-SVID 또는 Anthropic 조직이 신뢰하는 발급자의 표준 OIDC 토큰)입니다.

교환은 RFC 7523(JWT 베어러 부여)를 따릅니다. 워크로드는 일치시킬 페더레이션 규칙(fdrl_), 역할을 수행할 서비스 계정(svac_), 교환이 속한 조직 등 세 가지 식별자와 함께 Anthropic의 토큰 엔드포인트에 어설션을 제공합니다. 코드에서 교환의 핵심은 JSON 본문이 있는 POST입니다.

type exchangeRequest struct {
    GrantType        string `json:"grant_type"`         // "urn:ietf:params:oauth:grant-type:jwt-bearer"
    Assertion        string `json:"assertion"`          // 검증된 JWT-SVID 또는 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"`
}

응답은 RFC 6749 토큰 응답입니다. 발행된 토큰에는 sk-ant-oat 접두사(OAT = OAuth 액세스 토큰), 선언된 범위(전체 비관리 API 액세스의 경우 workspace:developer, MCP 터널 관리의 경우 org:manage_tunnels) 및 60초~24시간의 수명이 포함됩니다.

새로 고침 토큰이 없습니다. 발행된 토큰이 만료되면 워크로드는 어설션을 다시 제시하고 교환을 다시 실행해야 합니다. 이는 의도적인 것입니다. 어설션 자체가 증명되므로(SPIFFE 워크로드 API 또는 OIDC 공급자에 의해 업스트림 확인됨) 모든 재교환은 재증명입니다. 손상된 토큰은 남은 수명 동안에만 유용하며 공격자가 이를 확장하기 위해 이용할 수 있는 새로 고침 경로가 없습니다.

결과는 세션별 ID입니다. 각 Claude Code 세션은 자체 어설션을 교환하고 자체 단기 토큰을 수신하며 고유한 주체로 인증합니다. 감사 추적은 어떤 서비스 계정이 작동했는지, 어떤 페더레이션 규칙에 바인딩되었는지, 어떤 작업 영역으로 범위가 지정되었는지 기록합니다.

정적 키 섀도우 페더레이션 풋건 감지

WIF를 배포하는 것만으로는 충분하지 않습니다. 또한 환경의 어떤 것이 자동으로 이를 우회하는 경우도 감지해야 합니다. 커넥터는 런타임 환경에서 정적 자격 증명(ANTHROPIC_API_KEY 또는 ANTHROPIC_AUTH_TOKEN)이 있는지 검사하고 연합이 동시에 사용 중인지 확인합니다(선언된 연합 규칙 또는 ANTHROPIC_IDENTITY_TOKEN_FILE 신호를 통해). 두 조건이 모두 충족되면 심각도가 높은 거버넌스 결과가 표시됩니다.

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는 어떤 변수가 우선하는지 식별한다 — 값은 기록하지 않는다
    }, true
}

결과의 세부 해시는 키 값을 삽입하지 않고 어떤 정적 변수가 존재하고 어떤 페더레이션 신호가 섀도잉되는지 기록합니다. 가면을 쓴 형태도 아닙니다. 해시는 실행 전반에 걸쳐 안정적이므로 거버넌스 엔진이 해시를 중복 제거하고 SIEM이 사례별로 쿼리할 수 있습니다.

사용 중인 페더레이션이 없는 정적 키는 단지 정적 키일 뿐입니다. 즉, 커넥터가 이에 플래그를 지정하지 않습니다. 둘 다 존재하는 경우에만 결과가 실행됩니다. 이는 운영자가 페더레이션이 활성화되어 있다고 믿는 특정 구성이고 그렇지 않기 때문입니다.

조정 루프: 선언된 것과 실제적인 것

정적 키 풋건을 감지하는 것은 그림의 절반입니다. 나머지 절반은 페더레이션 구성 자체가 드리프트되지 않았는지 확인하는 것입니다. 커넥터는 선언된 기준(운영자가 명시적으로 관리되는 것으로 선언하는 페더레이션 규칙)을 유지 관리하고 이를 Anthropic 조직의 WIF 구성의 실시간 상태와 비교합니다.

실시간 상태는 세 개의 WIF 관리 API 엔드포인트에서 제공됩니다.

  • GET /v1/organizations/service_accounts — 페더레이션 규칙이 대상으로 하는 서비스 계정(svac_)
  • GET /v1/organizations/federation_issuers — 조직이 신뢰하는 OIDC/SPIFFE 발급자(fdis_)
  • GET /v1/organizations/federation_rules — 발급자를 서비스 계정에 바인딩하는 규칙(fdrl_)

이러한 엔드포인트에는 org:admin OAuth 전달자 토큰이 필요합니다. 이는 명단에서 읽는 sk-ant-admin 관리 API 키와는 다른 자격 증명입니다. WIF Admin API는 Admin API 키를 명시적으로 거부하므로 커넥터는 조정을 위해 별도의 인증된 클라이언트를 사용합니다.

선언된 항목과 라이브 항목 간의 차이로 인해 다음과 같은 7가지 범주의 결과가 생성됩니다.

드리프트 케이스의미심각도
undeclared_live_rule운영자가 선언하거나 관리하지 않는 실제 규칙높음
declared_rule_not_live더 이상 업스트림에 존재하지 않는 선언된 규칙중간
scope_drift라이브 범위가 선언된 범위에서 벗어났습니다.중간(조직 전체로 확장된 경우 높음)
lifetime_drift라이브 토큰 수명이 선언된 수명과 다릅니다.중간(신고된 것보다 길면 높음)
over_broad_subject실제 주제 제약이 없는 실시간 규칙중간
orphan_rule누락된 발급기관 또는 서비스 계정을 참조하는 규칙중간
orphan_issuer규칙 없이 참조되는 발급자낮음

두 가지 사례는 자동으로 높은 심각도로 에스컬레이션됩니다. 즉, 운영자가 선언하지 않은 조직 전체 또는 관리 범위로 확장된 라이브 범위와 관리되는 기준보다 긴 라이브 토큰 수명입니다. 둘 다 운영자가 승인한 것 이상으로 폭발 반경을 넓힙니다. 범위 정규화(자르기, 중복 제거, 정렬)는 공백이나 순서 차이로 인한 거짓 긍정을 방지합니다.

org:admin 토큰이 구성되지 않으면 조정 단계가 실행되지 않습니다. 커넥터는 선언된 전용 기준으로 작동하며 적용 범위에 대해 정직합니다. 즉, 라이브 목록을 결코 조작하지 않습니다. 라이브 API에 연결할 수 없는 경우(네트워크 오류, 토큰 만료) 단일 reconciliation_unavailable 결과를 내보내고 계속됩니다. 명단 승인 및 풋건 감지는 org:admin 토큰의 상태와 결합되어서는 안 됩니다.

읽기 우선 및 최소 데이터

커넥터는 엄격한 데이터 최소화 계약을 따릅니다. 모든 API 호출은 GET입니다. Anthropic 객체를 생성, 업데이트 또는 삭제하지 않습니다. ID, 이름, 이메일, 역할, 주요 힌트 등 ID 메타데이터만 전달합니다. 절대 중요한 비밀이 아닙니다. 절대 개인 키가 아닙니다. 유휴 상태에서는 발행된 토큰이 아닙니다.

WIF 교환에서 발행된 토큰은 호출자에게 반환되며 커넥터에 의해 기록되거나 유지되거나 방출되지 않습니다. 거버넌스 원장에 도달하는 유일한 기록은 의도적으로 토큰을 전달하지 않는 ExchangeAudit 구조체입니다.

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

실시간 조정에도 동일한 최소화가 적용됩니다. 커넥터가 페더레이션 발급자의 JWKS 구성을 읽으면 검색 모드(discovery, explicit_url 또는 inline)와 사용자 지정 CA 인증서가 고정되었는지 여부라는 두 가지 부울로 응답이 줄어듭니다. 인라인 JWK 자료(공개 키이지만 크기가 크고 거버넌스 결정에 필요하지 않음)는 저장되거나 방출된 필드로 디코딩되지 않습니다. CA 인증서 PEM은 존재 플래그를 파생하기 위해서만 디코딩되며 즉시 삭제됩니다.

페더레이션 규칙의 CEL 조건은 상태 분석을 위해 수행되지만(규칙의 CEL 표현식은 보안 경계의 일부임) 평가되지는 않습니다. 커넥터에는 CEL 엔진 종속성이 없습니다. 평가는 별도의 문제입니다.

이것이 가능하게 하는 것

정적 키는 인증과 ID를 결합합니다. 모든 세션은 동일한 주체이고 모든 토큰은 영원히 유지되며 도트 파일에 키가 있으면 보호한다고 생각했던 모든 연합이 자동으로 비활성화됩니다.

WIF는 둘을 분리합니다. 인증은 워크로드가 주장하는 사람임을 증명하는 입증된 어설션을 통해 이루어집니다. ID의 범위는 세션(단기 토큰, 특정 서비스 계정, 특정 작업공간, 선언된 범위)으로 지정됩니다. 토큰이 만료되면 워크로드가 다시 증명됩니다. 구성이 드리프트되면 조정 루프가 gap를 나타냅니다. 정적 키가 전체 메커니즘을 섀도잉하는 경우 커넥터는 이를 감지하고 사건 발견이 되기 전에 이를 보고합니다.

그 결과 자격 증명이 만료되고, 세션이 귀속되며, 거버넌스 가정이 누군가가 의도한 상태뿐만 아니라 조직의 실제 상태에 대해 지속적으로 확인되는 ID 모델이 탄생했습니다.


ID 커넥터, WIF 교환 및 풋건 감지는 ID 거버넌스 모듈의 일부입니다. 더 넓은 보안 모델(원장, 액세스 맵, 읽기 우선 컬렉션 아키텍처)은 보안을 참조하세요.

관련 글

후크 PEP 내부: Claude Code 내부 거부 폐쇄 정책

PEP가 모든 Claude Code 후크 이벤트를 게이팅, 컨텍스트 또는 관찰로 분류하고, 이벤트별로 올바른 출력 스키마를 연결하고, 알 수 없는 이벤트를 거부하고 닫는 방법입니다.

자주 묻는 질문

정적 키에는 섀도우 페더레이션을 위한 유효한 API 키가 포함되어야 합니까?

아니요. Anthropic의 자격 증명 우선 순위는 유효성이 아닌 존재 여부에 따라 결정됩니다. 빈 ANTHROPIC_API_KEY=""는 채워진 키와 마찬가지로 우선 순위 슬롯을 획득합니다. 해결 순서에서 페더레이션 계층 위에 위치하므로 런타임이 증명된 경로를 통과하지 않습니다. 커넥터는 해당 값이 비어 있지 않은지 여부가 아니라 환경 변수가 설정되었는지(os.LookupEnv) 확인하여 이를 감지합니다. 빈 키는 인증에 실패하지만 실제 키만큼 철저하게 섀도우 페더레이션을 수행합니다.

실시간 조정을 위한 org:admin OAuth 토큰이 없으면 어떻게 되나요?

커넥터는 그것 없이도 작동합니다. 운영자가 페더레이션 구성에서 선언하는 내용을 정확하게 모델링하고, 관리되는 NHI 명단과 해당 선언에서 허용된 부여 에지를 내보내고, 정적 키 풋건 감지를 실행합니다. WIF 관리 API 엔드포인트는 org:admin OAuth 전달자 토큰 이외의 모든 것을 거부하기 때문에 실시간 조정 단계를 건너뜁니다. 적용 범위에 대해 정직하고 선언된 기준만 얻을 수 있습니다. 이는 실제 명단을 조작하지 않습니다.

에이전트가 무엇에 접근할 수 있는지 확인하세요

Olivares AI는 당신의 AI 환경을 위한 개방형 자체 호스팅 플랫폼입니다. 자체 인프라에 배포하고 보안 및 플랫폼 팀이 필요로 하는 액세스 맵을 확보하세요.