For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
기본 탐색 메뉴
Theme

Kubernetes용 워크로드 아이덴티티 페더레이션 구성

Kubernetes를 워크로드 아이덴티티 공급자로 사용하면 Kubernetes가 프로젝션한 서비스 계정 토큰을 유효 기간이 짧은 OpenAI 액세스 토큰으로 교환할 수 있습니다.

Kubernetes 설정

이 가이드에서는 Kubernetes 서비스 계정 토큰 프로젝션이 활성화되어 있다고 가정합니다. 최신 Kubernetes 릴리스에서는 이 기능을 기본으로 사용할 수 있습니다. OpenAI 워크로드 아이덴티티 페더레이션에는 프로젝션된 OIDC 호환 서비스 계정 토큰이 필요합니다. 시크릿에 저장된 기존 방식의 Kubernetes 서비스 계정 토큰은 지원되지 않습니다.

OpenAI API를 호출해야 하는 워크로드에는 Kubernetes ServiceAccount를 사용하세요. 아직 없다면 다음 명령어로 생성하세요.

kubectl create serviceaccount openai-wif --namespace default

Kubernetes 클러스터의 OIDC 발급자를 확인하세요.

kubectl get --raw /.well-known/openid-configuration | jq -r .issuer

JWKS를 직접 업로드해 OpenAI가 OIDC 발급자에서 JWKS를 자동으로 조회하지 않는 경우에도 이 발급자는 워크로드 아이덴티티 공급자에 설정한 발급자와 일치해야 합니다.

다음 명령어로 클러스터의 JWKS를 조회하고 반환된 키 집합을 저장하세요. 워크로드 아이덴티티 공급자를 구성할 때 필요합니다.

kubectl get --raw /openid/v1/jwks

프로젝션할 서비스 계정 토큰의 대상은 OpenAI가 요구하는 값으로 설정하고, 유효 기간은 워크로드에 맞게 지정하세요. OpenAI는 토큰의 발급자, 서명, 대상, 만료 시각을 검증합니다. 이 예시에서는 토큰 파일을 /var/run/secrets/tokens/token에 마운트합니다. 토큰의 대상은 https://api.openai.com/v1이며, 토큰은 3600초 후에 만료됩니다. 프로젝션된 토큰과 OpenAI 워크로드 아이덴티티 공급자의 대상 값이 일치하면 다른 값을 사용해도 됩니다.

apiVersion: v1
kind: Pod
metadata:
  name: openai-wif-app
  namespace: default
spec:
  serviceAccountName: openai-wif
  containers:
    - name: app
      image: my-image
      volumeMounts:
        - name: ksa-token
          mountPath: /var/run/secrets/tokens
          readOnly: true
  volumes:
    - name: ksa-token
      projected:
        sources:
          - serviceAccountToken:
              path: token
              audience: "https://api.openai.com/v1"
              expirationSeconds: 3600

토큰 확인

워크로드 아이덴티티 페더레이션을 구성하기 전에 프로젝션된 서비스 계정 토큰 하나를 로컬에서 디코딩해 클레임을 확인하세요. 프로젝션된 토큰이 마운트된 실행 중인 파드에서 토큰을 가져와 TOKEN 환경 변수로 내보내세요.

TOKEN=$(kubectl exec -n default openai-wif-app -- cat /var/run/secrets/tokens/token)
export TOKEN

이어서 다음 스크립트를 실행하세요.

const parts = process.env.TOKEN?.split(".") ?? [];
if (parts.length !== 3) {
  throw new Error("Expected a compact JWT with three segments");
}
if (!/^[A-Za-z0-9_-]+$/.test(parts[1]) || parts[1].length % 4 === 1) {
  throw new Error("JWT payload is not valid Base64URL");
}

const bytes = Buffer.from(parts[1], "base64url");
if (bytes.toString("base64url") !== parts[1]) {
  throw new Error("JWT payload is not valid Base64URL");
}
const decoded = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
const claims = JSON.parse(decoded);
if (claims === null || Array.isArray(claims) || typeof claims !== "object") {
  throw new Error("JWT payload is not a JSON object");
}
console.log(decoded);

이 명령어는 토큰 서명을 검증하지 않고 JWT 페이로드를 디코딩합니다. 프로덕션 토큰은 로컬 디코더로 확인하고 타사 도구에 붙여넣지 마세요.

Kubernetes가 프로젝션한 서비스 계정 토큰을 디코딩하면 다음과 비슷한 결과가 나옵니다.

{
  "iss": "https://kubernetes.example.com",
  "aud": ["https://api.openai.com/v1"],
  "sub": "system:serviceaccount:default:openai-wif",
  "iat": 1716235422,
  "exp": 1716239022,
  "kubernetes.io": {
    "namespace": "default",
    "serviceaccount": {
      "name": "openai-wif",
      "uid": "11111111-2222-3333-4444-555555555555"
    }
  }
}

디코딩한 페이로드를 보고 수신한 토큰의 값이 OpenAI에 설정한 발급자, 대상, 매핑 값과 일치하는지 확인하세요. 대부분의 구성 문제는 토큰을 교환하기 전에 iss, aud, sub 클레임을 확인하면 찾을 수 있습니다.

워크로드 아이덴티티 페더레이션 설정

OpenAI에서 Kubernetes 발급자에 대한 워크로드 아이덴티티 공급자를 생성한 다음, 프로젝션된 토큰의 속성과 일치하는 서비스 계정 매핑을 추가하세요.

먼저 워크로드 아이덴티티 공급자를 구성한 뒤 서비스 계정 매핑을 생성하세요.

워크로드 아이덴티티 공급자 설정

  1. 워크로드 아이덴티티 공급자를 생성하세요. 이름에는 kubernetes-prod처럼 고유한 값을 입력하세요. 설명에는 Production Kubernetes cluster처럼 관리자가 클러스터를 식별하는 데 도움이 되는 내용을 입력하세요.

  2. 발급자와 대상을 설정하세요. OIDC 발급자 URL에는 kubectl get --raw /.well-known/openid-configuration | jq -r .issuer 명령어가 반환한 발급자 URL을 입력하세요. 이 값은 프로젝션된 토큰의 iss 클레임과 일치해야 합니다. 대상에는 프로젝션된 서비스 계정 토큰 볼륨에 설정한 대상 식별 문자열을 그대로 입력하세요. 이 예시에서 대상 값은 https://api.openai.com/v1입니다.

  3. Kubernetes JWKS를 업로드하세요. 업로드한 JWKS로 토큰 검증을 활성화한 다음 JWKS JSON에 kubectl get --raw /openid/v1/jwks의 출력을 입력하세요. OpenAI는 이 공개 키 집합으로 Kubernetes가 프로젝션한 서비스 계정 토큰을 검증합니다. 최상위 keys 필드를 포함한 전체 키 집합을 업로드하세요.

    참고: 자체 호스팅 Kubernetes 클러스터에서는 OpenAI가 로컬 JWKS 모드만 지원합니다. 클러스터가 반환한 JWKS를 업로드하세요. OpenAI는 설정된 발급자에 대해 OIDC 검색을 수행하지 않습니다. 이 모드에서도 OpenAI는 설정된 발급자와 토큰의 iss 필드를 비교합니다.

    클러스터에서 서비스 계정 서명 키를 교체하면 워크로드 아이덴티티 공급자 설정에서 업로드한 JWKS를 업데이트하세요. 설정된 JWKS에 없는 키로 서명한 토큰은 거부됩니다. JWKS에 활성 공개 키가 여러 개 있으면 keys 배열 전체를 포함하세요.

  4. 매핑에 파생 속성이 필요한 경우에만 속성 변환을 추가하세요. sub, aud, iss 같은 토큰의 원본 클레임은 매핑 조건에 직접 사용할 수 있습니다. 원본 클레임 대신 변환된 속성으로 일치 여부를 판단할 경우 대시보드가 openai. 접두사를 자동으로 붙입니다. 예를 들어 속성 이름에 workload_subject를, 표현식에 assertion.sub를 입력하면 openai.workload_subject가 생성됩니다. 원본 토큰 클레임의 이름이 이미 openai.로 시작하더라도 해당 변환을 설정하지 않으면 openai. 매핑 키를 평가할 때 그 클레임은 무시됩니다.

서비스 계정 매핑 설정

  1. 서비스 계정 매핑을 생성하세요. 이름에는 openai-mapping-kubernetes처럼 해당 워크로드 아이덴티티 공급자 내에서 고유한 값을 입력하세요. 설명에는 Workload Identity Provider Mapping for Kubernetes Workloads처럼 어떤 워크로드가 이 매핑을 사용할 수 있는지 적으세요.

  2. Kubernetes 서비스 계정의 주체가 일치하도록 설정하세요. 키에는 sub를, 값에는 system:serviceaccount:default:openai-wif를 입력하세요. Kubernetes 서비스 계정의 주체 형식은 system:serviceaccount:<namespace>:<service-account-name>입니다.

  3. OpenAI에서 매핑할 대상을 선택하세요. 프로젝트에서 대상 서비스 계정이 속한 OpenAI 프로젝트를 선택하세요. 서비스 계정에서 kubernetes-prod-openai-wif처럼 Kubernetes 워크로드가 사용할 OpenAI 서비스 계정을 선택하세요. 기존 계정을 재사용하는 대신 이 매핑을 위한 서비스 계정을 새로 만들려면 Create a new service account in this project를 선택하세요.

  4. 필요한 경우 API 권한을 제한하세요. 권한에서 api.model.request, api.vector_store.read 등 필요한 권한을 선택하면 이 매핑을 통해 발급되는 액세스 토큰의 권한 범위를 더 좁힐 수 있습니다. WIF에만 적용되는 범위 제한을 추가하지 않으려면 권한을 비워 두세요. 이 경우에도 토큰에는 매핑된 서비스 계정의 권한이 적용됩니다.

코드에서 토큰 사용

OpenAI SDK 클라이언트가 프로젝션된 Kubernetes 토큰을 읽고 OpenAI가 발급하는 액세스 토큰으로 교환하도록 구성하세요.

SDK의 워크로드 아이덴티티 페더레이션 공급자에 /var/run/secrets/tokens/token처럼 토큰이 마운트된 경로를 주체 토큰의 소스로 지정하세요. SDK는 해당 Kubernetes 토큰을 OpenAI가 발급하는 액세스 토큰으로 교환하고, 이 OpenAI 토큰으로 API 요청을 인증합니다.

다음 예시에서는 사용자 지정 주체 토큰 공급자로 OpenAI 클라이언트를 초기화합니다. 이 공급자는 마운트된 파일에서 Kubernetes가 프로젝션한 서비스 계정 토큰을 읽어 워크로드 아이덴티티 페더레이션의 주체 토큰으로 사용합니다.

Kubernetes가 프로젝션한 서비스 계정 토큰으로 인증하기
import { readFile } from "node:fs/promises";
import OpenAI from "openai";

const tokenPath = "/var/run/secrets/tokens/token";
const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;
const serviceAccountId = process.env.OPENAI_SERVICE_ACCOUNT_ID;

if (!identityProviderId || !serviceAccountId) {
  throw new Error(
    "Set OPENAI_IDENTITY_PROVIDER_ID and OPENAI_SERVICE_ACCOUNT_ID"
  );
}

function mountedServiceAccountTokenProvider(path) {
  return {
    tokenType: "jwt",
    getToken: async () => {
      const token = (await readFile(path, "utf8")).trim();
      if (!token) {
        throw new Error("The mounted service account token file is empty.");
      }
      return token;
    },
  };
}

const client = new OpenAI({
  workloadIdentity: {
    identityProviderId,
    serviceAccountId,
    provider: mountedServiceAccountTokenProvider(tokenPath),
  },
});

const response = await client.responses.create({
  model: "gpt-5.6-terra",
  input: "Say hello from Kubernetes workload identity federation.",
});

console.log(response.output_text);

Kubernetes 권장 사항

  • OIDC 발급자 URL을 안정적으로 유지하세요. 발급자 URL은 프로젝션된 서비스 계정 토큰의 iss 클레임과 일치해야 하며, 클러스터 업그레이드나 유지보수 중에도 같은 URL을 유지하는 것이 좋습니다.
  • 서명 키를 안전하게 보호하세요. 클러스터의 서비스 계정 서명 키에 접근할 수 있는 사람은 누구나 OpenAI가 수락할 수 있는 토큰을 발급할 수 있습니다.
  • OpenAI 연동에는 전용 서비스 계정을 사용하세요. 관련 없는 인프라나 애플리케이션에 접근할 때 쓰는 서비스 계정은 재사용하지 마세요.
  • 업로드한 JWKS를 최신 상태로 유지하세요. 로컬 JWKS 모드에서는 OpenAI가 설정된 JWKS로 워크로드 아이덴티티 토큰을 검증하므로, 새 서명 키로 교체하기 전에 워크로드 아이덴티티 공급자의 JWKS를 업데이트하세요.
  • 사용자 지정 클레임은 단순하게 유지하세요. 매핑 조건에는 sub, aud 같은 표준 클레임이나 이 클레임을 직접 변환해 얻은 속성을 사용하는 것이 좋습니다.
  • 네임스페이스 소유권을 보안 모델에 반영하세요. 네임스페이스 관리자가 서비스 계정을 생성할 수 있다면 매핑 범위를 적절히 제한해 의도하지 않은 권한 상승을 방지하세요.
  • 발급자와 서명 키의 변경 사항을 모니터링하세요. 워크로드 아이덴티티 공급자의 JWKS를 업데이트하지 않고 서명 키를 교체하면 토큰 교환이 실패할 수 있습니다.