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

GitHub Actions용 워크로드 ID 페더레이션 구성

GitHub에서 발급한 OIDC 토큰을 유효 기간이 짧은 OpenAI 액세스 토큰으로 교환하면 GitHub Actions를 워크로드 ID 공급자로 사용할 수 있습니다. 이렇게 하면 워크플로우에서 GitHub 시크릿에 장기 API 키를 저장하지 않고도 OpenAI API에 인증할 수 있습니다.

워크플로우 작업에 id-token: write 권한이 있고 해당 작업이 ID 토큰을 요청하면 GitHub는 서명된 OIDC JWT를 발급할 수 있습니다. OpenAI는 토큰의 발급자, 대상, 서명, 매핑 속성을 검증한 후 OpenAI 액세스 토큰을 발급합니다.

GitHub Actions 설정

워크플로우 또는 작업에 GitHub OIDC 토큰을 요청할 권한을 부여하세요.

permissions:
  id-token: write
  contents: read

id-token: write 권한이 있으면 작업에서 OIDC JWT를 요청할 수 있습니다. 이 권한으로 리포지터리의 콘텐츠를 수정할 수는 없습니다. contents: read 권한은 actions/checkout에 필요합니다.

토큰을 요청할 때는 OpenAI 워크로드 ID 공급자에 설정한 대상 값을 정확히 지정하세요. 사용자 지정 JavaScript 액션에서는 core.getIDToken("your-wif-audience")을 호출할 수 있고, 셸 단계에서는 GitHub의 OIDC 요청 URL을 직접 호출할 수 있습니다. https://api.openai.com/v1처럼 URL 예약 문자가 포함된 대상 값은 URL 인코딩한 후 요청 URL에 추가하세요.

AUDIENCE="https://api.openai.com/v1"
ENCODED_AUDIENCE=$(jq -rn --arg audience "$AUDIENCE" '$audience | @uri')

TOKEN=$(curl -sSf -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
  "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=${ENCODED_AUDIENCE}" | jq -r .value)
export TOKEN

GitHub OIDC 토큰의 주요 클레임은 다음과 같습니다.

  • iss: 토큰 발급자입니다. GitHub Actions의 발급자는 https://token.actions.githubusercontent.com입니다.
  • aud: 워크플로우에서 요청한 대상 값입니다. your-wif-audience 또는 https://api.openai.com/v1처럼 워크플로우에서 요청한 값과 정확히 일치하는 값만 허용하도록 OpenAI를 구성하세요.
  • sub: 토큰의 주체를 나타내는 기본 문자열입니다. GitHub는 리포지터리, 브랜치, 태그, pull request, 환경 등의 워크플로우 메타데이터로 이 문자열을 구성합니다.
  • repository: 워크플로우를 실행하는 리포지터리입니다. 예를 들면 my-org/my-repo입니다.
  • repository_owner: 리포지터리를 소유한 조직 또는 사용자입니다. 예를 들면 my-org입니다.
  • ref: 워크플로우 실행을 트리거한 Git ref입니다. 예를 들면 refs/heads/main 또는 refs/tags/v1.0.0입니다.
  • workflow: 워크플로우 클레임입니다. GitHub가 작업의 토큰에 포함한 실제 클레임 값을 사용하세요. 예를 들어 값이 deploy이면 그대로 사용하세요.
  • workflow_ref: 워크플로우 파일 경로와 ref입니다. 예를 들면 my-org/my-repo/.github/workflows/deploy.yml@refs/heads/main입니다.
  • environment: 작업에서 환경을 사용할 때 토큰에 포함되는 GitHub 환경 이름입니다. 예를 들면 production입니다.
  • run_id, run_number, run_attempt, job_workflow_ref: 감사나 고급 신뢰 규칙 설정에 활용할 수 있는 실행 및 작업 식별자입니다.

전체 클레임 목록과 주체 문자열 형식은 GitHub의 OpenID Connect 참조 문서를 참고하세요.

토큰 확인

워크로드 ID 페더레이션을 구성하기 전에 GitHub OIDC 토큰을 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 페이로드를 디코딩합니다. 프로덕션 토큰은 로컬 디코더로 확인하고 서드 파티 도구에 붙여 넣지 마세요. GitHub OIDC 토큰 원문이나 교환으로 얻은 OpenAI 액세스 토큰을 절대 로그에 남기지 마세요.

GitHub Actions OIDC 토큰을 디코딩하면 다음과 비슷한 결과가 나옵니다.

{
  "iss": "https://token.actions.githubusercontent.com",
  "aud": "https://api.openai.com/v1",
  "sub": "repo:my-org/my-repo:environment:production",
  "repository": "my-org/my-repo",
  "repository_owner": "my-org",
  "ref": "refs/heads/main",
  "workflow": "deploy",
  "workflow_ref": "my-org/my-repo/.github/workflows/deploy.yml@refs/heads/main",
  "environment": "production",
  "run_id": "1234567890",
  "run_attempt": "1"
}

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

워크로드 ID 페더레이션 설정

OpenAI에서 GitHub Actions용 워크로드 ID 공급자를 만든 다음, 신뢰하는 GitHub 워크플로우의 클레임과 일치하는 서비스 계정 매핑을 추가하세요.

먼저 워크로드 ID 공급자를 구성한 후 서비스 계정 매핑을 만드세요.

워크로드 ID 공급자 설정

  1. 워크로드 ID 공급자를 만드세요. 이름에 github-actions-prod처럼 고유한 값을 입력하세요. 설명에는 Production GitHub Actions workflows처럼 관리자가 공급자를 식별할 수 있는 내용을 입력하세요.

  2. 발급자와 대상을 설정하세요. OIDC 발급자 URL에 https://token.actions.githubusercontent.com을 입력하세요. 대상에는 your-wif-audience 또는 https://api.openai.com/v1처럼 워크플로우에서 요청하는 대상 값을 정확히 입력하세요.

  3. GitHub OIDC 검색을 사용하세요. 토큰 검증에 업로드한 JWKS 사용 옵션은 꺼 두세요. OpenAI는 GitHub의 OIDC 검색 메타데이터와 JWKS를 사용해 GitHub가 서명한 토큰을 검증합니다.

  4. 파생 매핑 속성이 필요한 경우에만 속성 변환을 추가하세요. repository, ref, workflow 같은 GitHub 원본 클레임은 매핑의 일치 조건에 직접 사용할 수 있습니다. 파생 속성을 만들면 대시보드가 openai. 접두사를 자동으로 붙입니다. 예를 들어 속성 이름으로 github_repository를 입력하고 표현식으로 assertion.repository를 지정하면 openai.github_repository가 생성됩니다. 원본 토큰에서 이미 openai.로 시작하는 클레임은 해당 변환을 구성하지 않으면 openai. 매핑 키에 사용되지 않습니다.

서비스 계정 매핑 설정

  1. 서비스 계정 매핑을 만드세요. 이름에 github-actions-main-deploy처럼 해당 워크로드 ID 공급자 내에서 고유한 값을 입력하세요. 설명에는 Production deploy workflow on main처럼 어떤 워크플로우가 매핑을 사용할 수 있는지 명시하세요.

  2. 클레임 값이 정확히 일치하도록 조건을 추가하세요. 일치 여부를 확인할 GitHub 클레임마다 키와 값을 입력할 행을 하나씩 추가하세요. OpenAI는 설정한 모든 행의 조건이 충족되어야 액세스 토큰을 발급합니다. 프로덕션 배포 워크플로우에서는 다음과 같은 조건을 사용하세요.

    iss == "https://token.actions.githubusercontent.com"
    aud == "https://api.openai.com/v1"
    repository == "my-org/my-repo"
    ref == "refs/heads/main"
    workflow_ref == "my-org/my-repo/.github/workflows/deploy.yml@refs/heads/main"

    높은 권한을 부여하는 매핑에는 workflow_ref를 우선 사용하세요. 관리자가 신뢰하려는 대상은 대개 특정 워크플로우 파일 경로와 ref입니다. workflow가 나타내는 워크플로우 이름은 변경할 수 있고 여러 워크플로우 파일에서 같은 이름을 사용할 수도 있습니다.

    매핑 UI에서는 각 조건을 키와 값으로 나누어 한 행씩 입력하세요. 예를 들어 한 행에는 키 repository, 값 my-org/my-repo를 입력하고, 다른 행에는 키 ref, 값 refs/heads/main을 입력하세요. 또 다른 행에는 키 workflow_ref, 값 my-org/my-repo/.github/workflows/deploy.yml@refs/heads/main을 입력하세요. 작업에서 GitHub 환경을 사용한다면 키 environment, 값 production인 행도 추가하세요.

    주의: repository_owner == "my-org"만 확인하는 식으로 매핑 범위를 지나치게 넓게 설정하지 마세요. 해당 소유자의 네임스페이스에 속한 모든 리포지터리가 OpenAI 액세스 토큰을 발급받을 수 있어야 하는 경우에만 이런 매핑을 사용하세요.

  3. 매핑할 OpenAI 대상을 선택하세요. 프로젝트에는 대상 서비스 계정이 속한 OpenAI 프로젝트를 지정하세요. 서비스 계정에는 github-actions-prod-deploy처럼 GitHub 워크플로우에서 사용할 수 있는 OpenAI 서비스 계정을 지정하세요.

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

워크플로우에서 토큰 사용

GitHub OIDC 토큰을 요청하고 이를 OpenAI가 발급하는 액세스 토큰으로 교환하도록 OpenAI SDK 클라이언트를 구성하세요.

워크플로우에서 id-token: write 권한을 부여하고 워크로드 ID 페더레이션 설정을 SDK 코드에 전달해야 합니다. SDK는 GitHub가 작업에 제공하는 ACTIONS_ID_TOKEN_REQUEST_URL 및 ACTIONS_ID_TOKEN_REQUEST_TOKEN 환경 변수를 사용해 GitHub OIDC 토큰을 요청합니다. 그런 다음 교환으로 얻은 OpenAI 액세스 토큰으로 API 요청을 인증합니다.

예를 들어 다음과 같은 워크플로우에서 애플리케이션 코드를 실행하세요.

name: deploy

on:
  push:
    branches:
      - main
  workflow_dispatch:

permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4

      - name: Run OpenAI SDK code
        env:
          OPENAI_WIF_AUDIENCE: ${{ vars.OPENAI_WIF_AUDIENCE }}
          OPENAI_IDENTITY_PROVIDER_ID: ${{ vars.OPENAI_IDENTITY_PROVIDER_ID }}
          OPENAI_SERVICE_ACCOUNT_ID: ${{ vars.OPENAI_SERVICE_ACCOUNT_ID }}
        run: node ./scripts/call-openai.js

OPENAI_WIF_AUDIENCE, OPENAI_IDENTITY_PROVIDER_ID, OPENAI_SERVICE_ACCOUNT_ID를 GitHub Actions 변수로 저장하세요. 이 값들은 공급자와 서비스 계정을 식별하며, 그 자체로 인증에 사용할 수 있는 전달자 자격 증명은 아닙니다.

다음 예제는 사용자 지정 주체 토큰 공급자로 OpenAI 클라이언트를 초기화합니다. 공급자는 설정된 대상에 맞는 GitHub OIDC 토큰을 요청하고, 이를 워크로드 ID 페더레이션의 주체 토큰으로 사용합니다.

GitHub Actions OIDC 토큰으로 인증하기
import OpenAI from "openai";

const identityProviderId = process.env.OPENAI_IDENTITY_PROVIDER_ID;
const serviceAccountId = process.env.OPENAI_SERVICE_ACCOUNT_ID;
const audience = process.env.OPENAI_WIF_AUDIENCE;
const requestURL = process.env.ACTIONS_ID_TOKEN_REQUEST_URL;
const requestToken = process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN;

if (
  !identityProviderId ||
  !serviceAccountId ||
  !audience ||
  !requestURL ||
  !requestToken
) {
  throw new Error(
    "Set OPENAI_IDENTITY_PROVIDER_ID, OPENAI_SERVICE_ACCOUNT_ID, OPENAI_WIF_AUDIENCE, and run inside GitHub Actions with id-token: write"
  );
}

function githubActionsOIDCTokenProvider(requestURL, requestToken, audience) {
  return {
    tokenType: "jwt",
    getToken: async () => {
      const url = new URL(requestURL);
      url.searchParams.set("audience", audience);

      const response = await fetch(url, {
        headers: { Authorization: `bearer ${requestToken}` },
      });

      if (!response.ok) {
        throw new Error(
          `Failed to request GitHub OIDC token: ${response.status} ${response.statusText}`
        );
      }

      const body = await response.json();
      if (!body.value) {
        throw new Error("GitHub OIDC token response did not include a value.");
      }

      return body.value;
    },
  };
}

const client = new OpenAI({
  workloadIdentity: {
    identityProviderId,
    serviceAccountId,
    provider: githubActionsOIDCTokenProvider(
      requestURL,
      requestToken,
      audience
    ),
  },
});

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

console.log(response.output_text);

GitHub Actions 권장 사항

  • 프로덕션 배포에는 환경 보호 규칙을 사용하세요. 워크플로우에서 프로덕션 OpenAI 리소스에 접근하려면 승인을 받거나 브랜치 제한 조건을 충족하도록 설정하세요.
  • 리포지터리별로 매핑을 제한하세요. 가능하면 조직 내 모든 리포지터리에 접근 권한을 부여하는 대신 개별 리포지터리를 식별하는 클레임이 일치하는지 확인하세요.
  • 브랜치 또는 워크플로우별로 매핑을 제한하세요. repository, ref, environment, workflow_ref 등의 클레임이 일치할 때만 토큰을 발급하도록 설정하는 방안을 고려하세요.
  • CI/CD와 프로덕션 워크로드에는 별도의 OpenAI 서비스 계정을 사용하세요. 빌드 파이프라인에는 배포된 애플리케이션과 다른 권한이 필요한 경우가 많습니다.
  • 신뢰할 수 없는 포크에서 제출한 pull requests에는 접근 권한을 부여하지 마세요. 포크에서 제출한 pull requests는 공격자가 제어하는 코드를 실행할 수 있으므로 프로덕션 자격 증명을 제공해서는 안 됩니다.
  • 토큰 교환은 인증이 필요한 시점에 수행하세요. GitHub OIDC 토큰은 일시적인 인증을 위한 것이므로 필요할 때만 교환하세요.
  • 리포지터리 소유권 변경을 감사하세요. 리포지터리 이전, 이름 변경, 권한 변경은 기존 매핑이 전제하는 보안 조건에 영향을 줄 수 있습니다.
  • 클레임 값이 정확히 일치하는지 확인하세요. 조직 전체를 신뢰하는 대신 repository, ref, environment 같은 클레임의 일치 여부를 기준으로 접근을 허용하세요.