InfoGrab DocsInfoGrab Docs

ID 토큰을 사용한 OpenID Connect(OIDC) 인증

요약

ID 토큰은 GitLab CI/CD가 생성하는 JSON 웹 토큰(JWT)입니다. 예를 들어 ID 토큰을 사용해 HashiCorp Vault로 인증하는 흐름은 다음 다이어그램과 같이 요약됩니다: ID 토큰은 secrets 키워드에서도 사용됩니다.

ID 토큰은 GitLab CI/CD가 생성하는 JSON 웹 토큰(JWT)입니다. CI/CD job은 ID 토큰을 사용해 서드파티 서비스와 OIDC 인증을 수행할 수 있습니다. 예를 들면 다음과 같습니다:

예를 들어 ID 토큰을 사용해 HashiCorp Vault로 인증하는 흐름은 다음 다이어그램과 같이 요약됩니다:

Mermaid 다이어그램 (17줄)
소스 코드 보기
sequenceDiagram
    participant GitLab as GitLab CI/CD
    participant Runner as GitLab Runner
    participant Vault as HashiCorp Vault
GitLab->>Runner: Generates an ID token (JWT) for the CI/CD job

Runner->>Vault: Runner authenticates with HashiCorp Vault using the token

Vault->>Vault: HashiCorp Vault verifies the token

Vault->>Vault: HashiCorp Vault checks bounded claims and attaches policies

Vault->>Runner: HashiCorp Vault returns the token

Runner->>Vault: Runner requests secrets from HashiCorp Vault
Vault-&gt;&gt;Runner: Returns secrets</code></pre></details></div>

ID 토큰은 secrets 키워드에서도 사용됩니다.

GitLab Duo Agent Platform의 flow와 외부 에이전트도 실행 중 서드파티 서비스로 인증하기 위해 id_tokens를 선언할 수 있습니다.

CI/CD job에서 ID 토큰 구성#

ID 토큰을 사용하려면 id_tokens 키워드로 CI/CD job을 구성합니다. 그런 다음 script, before_script, after_script 섹션에서 토큰을 사용할 수 있습니다.

예를 들면 다음과 같습니다:

job_with_id_tokens:
  id_tokens:
    FIRST_ID_TOKEN:
      aud: https://first.service.com
    SECOND_ID_TOKEN:
      aud: https://second.service.com
  script:
    - first-service-authentication-script.sh $FIRST_ID_TOKEN
    - second-service-authentication-script.sh $SECOND_ID_TOKEN

이 예시에서 두 토큰은 서로 다른 aud 클레임을 갖습니다. 서드파티 서비스는 바인딩된 audience와 일치하는 aud 클레임이 없는 토큰을 거부하도록 구성할 수 있습니다. 이 기능을 사용하면 토큰이 인증할 수 있는 서비스 수를 줄일 수 있습니다. 이를 통해 토큰이 탈취되었을 때의 심각도를 낮출 수 있습니다.

토큰 페이로드#

각 ID 토큰에는 다음 표준 클레임이 포함됩니다:

필드 설명
iss 토큰 발급자로, GitLab 인스턴스의 도메인입니다("issuer" 클레임).
sub 토큰의 주체입니다("subject" 클레임). 기본값은 project_path:{group}/{project}:ref_type:{type}:ref:{branch_name} 입니다. 프로젝트 API를 사용해 프로젝트 단위로 구성할 수 있습니다. sub 클레임에는 ref_protected 같은 추가 필드와, job 이 환경을 지정한 경우 environment_protected·deployment_tier 같은 환경 관련 필드가 포함될 수 있습니다. GitLab 18.7에서 도입되었습니다.
aud 토큰의 의도된 audience 입니다("audience" 클레임). ID 토큰 구성에서 지정합니다. 기본값은 GitLab 인스턴스의 도메인입니다.
exp 만료 시각입니다("expiration time" 클레임).
nbf 토큰이 유효해지는 시점입니다("not before" 클레임).
iat JWT가 발급된 시각입니다("issued at" 클레임).
jti 토큰의 고유 식별자입니다("JWT ID" 클레임).

토큰에는 GitLab 이 제공하는 커스텀 클레임도 포함됩니다:

필드 시점 설명
project_id 항상 job을 실행하는 프로젝트의 ID입니다. 머지 리퀘스트 파이프라인에서는 소스 프로젝트의 ID입니다.
project_path 항상 job을 실행하는 프로젝트의 경로입니다. 머지 리퀘스트 파이프라인에서는 소스 프로젝트의 경로입니다.
namespace_id 항상 job을 실행하는 프로젝트의 네임스페이스 ID입니다. 머지 리퀘스트 파이프라인에서는 소스 프로젝트의 네임스페이스 ID입니다.
namespace_path 항상 job을 실행하는 프로젝트의 네임스페이스 경로입니다. 머지 리퀘스트 파이프라인에서는 소스 프로젝트의 네임스페이스 경로입니다.
user_id 항상 job을 실행하는 사용자의 ID입니다.
user_login 항상 job을 실행하는 사용자의 사용자 이름입니다.
user_email 항상 job을 실행하는 사용자의 이메일입니다.
user_access_level 항상 job을 실행하는 사용자의 액세스 레벨입니다.
job_project_id 항상 job을 실행하는 프로젝트의 ID입니다. ID 기준으로 프로젝트 범위를 지정할 때 사용합니다. GitLab 18.4에서 도입되었습니다.
job_project_path 항상 job을 실행하는 프로젝트의 경로입니다. 경로 기준으로 프로젝트 범위를 지정할 때 사용합니다. GitLab 18.4에서 도입되었습니다.
job_namespace_id 항상 job을 실행하는 프로젝트의 네임스페이스 ID입니다. ID 기준으로 그룹 또는 사용자 수준 네임스페이스 범위를 지정할 때 사용합니다. GitLab 18.4에서 도입되었습니다.
job_namespace_path 항상 job을 실행하는 프로젝트의 네임스페이스 경로입니다. 경로 기준으로 그룹 또는 사용자 수준 네임스페이스 범위를 지정할 때 사용합니다. GitLab 18.4에서 도입되었습니다.
source_project_id 항상 소스 코드가 있는 프로젝트의 ID입니다. 머지 리퀘스트 파이프라인에서는 머지 리퀘스트의 소스 프로젝트 ID입니다. GitLab 19.5에서 도입되었습니다.
source_project_path 항상 소스 코드가 있는 프로젝트의 경로입니다. 머지 리퀘스트 파이프라인에서는 머지 리퀘스트의 소스 프로젝트 경로입니다. GitLab 19.5에서 도입되었습니다.
source_namespace_id 항상 소스 코드가 있는 프로젝트의 네임스페이스 ID입니다. 머지 리퀘스트 파이프라인에서는 머지 리퀘스트의 소스 프로젝트 네임스페이스 ID입니다. GitLab 19.5에서 도입되었습니다.
source_namespace_path 항상 소스 코드가 있는 프로젝트의 네임스페이스 경로입니다. 머지 리퀘스트 파이프라인에서는 머지 리퀘스트의 소스 프로젝트 네임스페이스 경로입니다. GitLab 19.5에서 도입되었습니다.
user_identities 사용자 환경설정 사용자의 외부 아이덴티티 목록입니다.
pipeline_id 항상 파이프라인의 ID입니다.
pipeline_source 항상 파이프라인 소스입니다.
job_id 항상 job의 ID입니다.
ref 항상 job의 Git ref입니다. 머지 리퀘스트 파이프라인에서는 소스 브랜치의 ref입니다.
ref_type 항상 Git ref 유형으로, branch 또는 tag 입니다.
ref_path 항상 job의 정규화된 ref입니다. 예를 들어 refs/heads/main 입니다. 머지 리퀘스트 파이프라인에서는 소스 브랜치의 ref 경로입니다.
ref_protected 항상 Git ref가 보호된 경우 true, 그렇지 않으면 false 입니다.
groups_direct 사용자가 0~200개 그룹의 직접 멤버인 경우 사용자가 직접 멤버로 속한 그룹의 경로입니다. 사용자가 200개를 초과하는 그룹의 직접 멤버인 경우 생략됩니다. 기능 플래그 ci_jwt_groups_direct가 GitLab 17.3에서 추가되었습니다. 기본적으로 비활성화되어 있습니다.
environment job 이 환경을 지정한 경우 이 job 이 배포하는 환경입니다.
environment_protected job 이 환경을 지정한 경우 배포된 환경이 보호된 경우 true, 그렇지 않으면 false 입니다.
deployment_tier job 이 환경을 지정한 경우 job 이 지정한 환경의 배포 티어입니다.
environment_action job 이 환경을 지정한 경우 job에 지정된 환경 작업(environment:action)입니다.
runner_id 항상 job을 실행하는 러너의 ID입니다.
runner_environment 항상 job에 사용된 러너의 유형입니다. gitlab-hosted 또는 self-hosted 중 하나입니다.
sha 항상 job의 커밋 SHA입니다.
ci_config_ref_uri 항상 최상위 파이프라인 정의의 ref 경로입니다. 예를 들어 gitlab.example.com/my-group/my-project//.gitlab-ci.yml@refs/heads/main 입니다. 파이프라인 정의가 동일한 프로젝트에 있지 않은 경우 이 클레임은 null 입니다.
ci_config_sha 항상 ci_config_ref_uri의 Git 커밋 SHA입니다. 파이프라인 정의가 동일한 프로젝트에 있지 않은 경우 이 클레임은 null 입니다.
project_visibility 항상 파이프라인이 실행 중인 프로젝트의 가시성입니다. internal, private, public 중 하나입니다.
job_source 항상 job 소스입니다. GitLab 18.9에서 도입되었습니다.
job_config job 이 정책에 의해 트리거된 경우 job의 출처에 대한 메타데이터입니다. 정책 job의 경우 정책 구성의 sha와 url을 포함합니다. GitLab 18.9에서 도입되었습니다.
{
  "namespace_id": "72",
  "namespace_path": "my-group",
  "project_id": "20",
  "project_path": "my-group/my-project",
  "user_id": "1",
  "user_login": "sample-user",
  "user_email": "sample-user@example.com",
  "user_identities": [
      {"provider": "github", "extern_uid": "2435223452345"},
      {"provider": "bitbucket", "extern_uid": "john.smith"}
  ],
  "pipeline_id": "574",
  "pipeline_source": "push",
  "job_id": "302",
  "ref": "feature-branch-1",
  "ref_type": "branch",
  "ref_path": "refs/heads/feature-branch-1",
  "ref_protected": "false",
  "groups_direct": ["mygroup/mysubgroup", "myothergroup/myothersubgroup"],
  "environment": "test-environment2",
  "environment_protected": "false",
  "deployment_tier": "testing",
  "environment_action": "start",
  "job_source": "push",
  "job_config": {
    "url": "https://gitlab.example.com/my-group/my-policy-project/-/blob/ab035e64eca9a7a85bd62e485d3593f52a2804ac/.gitlab/security-policies/policy.yml",
    "sha": "ab035e64eca9a7a85bd62e485d3593f52a2804ac"
  },
  "runner_id": 1,
  "runner_environment": "self-hosted",
  "sha": "714a629c0b401fdce83e847fc9589983fc6f46bc",
  "project_visibility": "public",
  "ci_config_ref_uri": "gitlab.example.com/my-group/my-project//.gitlab-ci.yml@refs/heads/main",
  "ci_config_sha": "714a629c0b401fdce83e847fc9589983fc6f46bc",
  "jti": "235b3a54-b797-45c7-ae9a-f72d7bc6ef5b",
  "iss": "https://gitlab.example.com",
  "iat": 1681395193,
  "nbf": 1681395188,
  "exp": 1681398793,
  "sub": "project_path:my-group/my-project:ref_type:branch:ref:feature-branch-1",
  "aud": "https://vault.example.com"
}

ID 토큰은 RS256으로 인코딩되며 전용 개인 키로 서명됩니다. 토큰의 만료 시간은 job의 타임아웃이 지정된 경우 해당 타임아웃으로, 지정되지 않은 경우 5분으로 설정됩니다.

클라우드 트러스트 정책에서 ID 토큰 클레임 사용#

GitLab을 OIDC ID 공급자로 연동(federate)하는 클라우드 공급자는 위 클레임을 트러스트 정책의 조건 키로 검증할 수 있습니다.

트러스트 정책을 작성할 때는 클라우드 공급자와 GitLab 오퍼링이 지원하는 경우, sub 같은 경로 기반 클레임과 함께 namespace_id·project_id 같은 안정적이고 고유한 식별자를 포함합니다. project_id는 전역적으로 고유하며 프로젝트가 존재하는 동안 동일하게 유지됩니다. namespace_id는 프로젝트가 현재 네임스페이스에 머무르는 동안 안정적으로 유지됩니다. 두 식별자 모두 경로와 무관하므로, 이를 포함한 트러스트 정책은 그룹이나 프로젝트 이름 변경 같은 경로 변경의 영향을 받지 않습니다.

GitLab.com의 AWS에서는 gitlab.com OIDC ID 공급자에 대해 다음 GitLab 클레임을 조건 키로 사용할 수 있습니다:

  • namespace_id
  • project_id
  • user_id
  • user_login
  • user_email
  • user_access_level
  • ref_protected
  • pipeline_source

이 조건 키는 gitlab.com OIDC ID 공급자에서만 사용할 수 있습니다. GitLab Self-Managed 나 GitLab Dedicated에서는 사용할 수 없으며, 이 경우 AWS 조건 키로는 sub 클레임만 지원됩니다.

사용자가 user_login 이나 user_email을 변경할 수 있으므로 이를 유일한 조건으로 사용하지 않습니다. 지원되는 클레임의 정확한 목록은 GitLab ID 공급자에 대해 AWS가 게시한 조건 키를 참고해 확인합니다.

sub, namespace_id, project_id를 사용하는 전체 AWS 트러스트 정책 예시는 AWS에서 OpenID Connect 구성을 참고합니다. HashiCorp Vault는 바운드 클레임을 참고합니다.

문제 해결#

400: missing token 상태 코드#

이 오류는 ID 토큰에 필요한 하나 이상의 기본 구성 요소가 누락되었거나 예상대로 구성되지 않았음을 나타냅니다.

문제를 찾으려면 관리자가 인스턴스의 exceptions_json.log에서 실패한 메서드에 대한 자세한 내용을 확인할 수 있습니다.

GitLab::Ci::Jwt::NoSigningKeyError#

exceptions_json.log 파일의 이 오류는 데이터베이스에 서명 키가 없어 토큰을 생성하지 못했기 때문일 가능성이 높습니다. 이 문제인지 확인하려면 인스턴스의 PostgreSQL 터미널에서 다음 쿼리를 실행합니다:

SELECT encrypted_ci_jwt_signing_key FROM application_settings;

반환된 값이 비어 있다면 다음 Rails 스니펫을 사용해 새 키를 생성하고 내부적으로 교체합니다:

  key = OpenSSL::PKey::RSA.new(2048).to_pem

  ApplicationSetting.find_each do |application_setting|
    application_setting.update(ci_jwt_signing_key: key)
  end

401: unauthorized 상태 코드#

이 오류는 인증 요청이 실패했음을 나타냅니다. GitLab 파이프라인에서 외부 서비스로 OpenID Connect(OIDC) 인증을 사용할 때 401 Unauthorized 오류는 다음과 같은 몇 가지 일반적인 이유로 발생할 수 있습니다:

  • ID 토큰 대신 $CI_JOB_JWT_V2 같은 지원 종료된 토큰을 사용했습니다. 자세한 내용은 구버전 JSON Web Token 지원 종료를 참고합니다.
  • .gitlab-ci.yml 파일과 외부 서비스의 OIDC ID 공급자 구성 간에 provider_name 값이 일치하지 않습니다.
  • GitLab 이 발급한 ID 토큰과 외부 서비스가 기대하는 값 사이에 aud(audience) 클레임이 누락되었거나 일치하지 않습니다.
  • GitLab CI/CD job에서 id_tokens: 블록을 활성화하거나 구성하지 않았습니다.

오류를 해결하려면 job 내부에서 토큰을 디코딩합니다:

echo $OIDC_TOKEN | cut -d '.' -f2 | base64 -d | jq .

다음을 확인합니다:

  • aud(audience)가 예상되는 audience(예: 외부 서비스의 URL)와 일치하는지 확인합니다.
  • sub(subject)가 서비스의 ID 공급자 설정에 매핑되어 있는지 확인합니다.
  • GitLab ID 토큰에는 기본적으로 preferred_username 이 포함되지 않는다는 점을 확인합니다.

오류: ID token issuance is disabled#

CI/CD job 이 ID 토큰을 요청할 때 다음 오류가 발생할 수 있습니다:

ID token issuance is disabled in CI because a project path in the `sub` claim was previously used by a different project.

구성된 sub 클레임에 다른 프로젝트가 이전에 사용했던 경로의 project_path, job_project_path 또는 source_project_path가 포함된 경우 GitLab은 ID 토큰 발급을 차단합니다. 이 제한은 새 프로젝트가 이전 프로젝트에 속한 외부 트러스트 정책을 물려받는 것을 방지합니다.

오류를 해결하려면 프로젝트 API를 사용해 ci_id_token_sub_claim_components를 설정하고 첫 번째 값으로 ID 구성 요소를 지정합니다. 사용하던 경로 구성 요소에 대응하는 ID 구성 요소를 사용합니다. project_path에는 project_id, job_project_path에는 job_project_id, source_project_path에는 source_project_id를 사용합니다. 예를 들면 다음과 같습니다.

{
  "ci_id_token_sub_claim_components": ["project_id", "ref_type", "ref"]
}

그 결과 sub 클레임은 다음과 같은 형식을 갖습니다:

project_id:<id>:ref_type:<type>:ref:<ref>

각 외부 서비스의 트러스트 정책을 새 subject에 맞게 업데이트합니다. 경로 이력이 예상과 다르다면 인스턴스 관리자에게 검토를 요청합니다.

클라우드 서비스 트러스트 정책 가이드는 프로젝트 ID를 subject로 사용을 참고합니다.

ID 토큰을 사용한 OpenID Connect(OIDC) 인증

GitLab v19.5
Tier: Free, Premium, Ultimate
Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
원문 보기

요약

ID 토큰은 GitLab CI/CD가 생성하는 JSON 웹 토큰(JWT)입니다. 예를 들어 ID 토큰을 사용해 HashiCorp Vault로 인증하는 흐름은 다음 다이어그램과 같이 요약됩니다: ID 토큰은 secrets 키워드에서도 사용됩니다.

ID 토큰은 GitLab CI/CD가 생성하는 JSON 웹 토큰(JWT)입니다. CI/CD job은 ID 토큰을 사용해 서드파티 서비스와 OIDC 인증을 수행할 수 있습니다. 예를 들면 다음과 같습니다:

예를 들어 ID 토큰을 사용해 HashiCorp Vault로 인증하는 흐름은 다음 다이어그램과 같이 요약됩니다:

Mermaid 다이어그램 (17줄)
소스 코드 보기
sequenceDiagram
    participant GitLab as GitLab CI/CD
    participant Runner as GitLab Runner
    participant Vault as HashiCorp Vault
GitLab-&gt;&gt;Runner: Generates an ID token (JWT) for the CI/CD job

Runner-&gt;&gt;Vault: Runner authenticates with HashiCorp Vault using the token

Vault-&gt;&gt;Vault: HashiCorp Vault verifies the token

Vault-&gt;&gt;Vault: HashiCorp Vault checks bounded claims and attaches policies

Vault-&gt;&gt;Runner: HashiCorp Vault returns the token

Runner-&gt;&gt;Vault: Runner requests secrets from HashiCorp Vault
Vault-&gt;&gt;Runner: Returns secrets</code></pre></details></div>

ID 토큰은 secrets 키워드에서도 사용됩니다.

GitLab Duo Agent Platform의 flow와 외부 에이전트도 실행 중 서드파티 서비스로 인증하기 위해 id_tokens를 선언할 수 있습니다.

CI/CD job에서 ID 토큰 구성#

ID 토큰을 사용하려면 id_tokens 키워드로 CI/CD job을 구성합니다. 그런 다음 script, before_script, after_script 섹션에서 토큰을 사용할 수 있습니다.

예를 들면 다음과 같습니다:

job_with_id_tokens:
  id_tokens:
    FIRST_ID_TOKEN:
      aud: https://first.service.com
    SECOND_ID_TOKEN:
      aud: https://second.service.com
  script:
    - first-service-authentication-script.sh $FIRST_ID_TOKEN
    - second-service-authentication-script.sh $SECOND_ID_TOKEN

이 예시에서 두 토큰은 서로 다른 aud 클레임을 갖습니다. 서드파티 서비스는 바인딩된 audience와 일치하는 aud 클레임이 없는 토큰을 거부하도록 구성할 수 있습니다. 이 기능을 사용하면 토큰이 인증할 수 있는 서비스 수를 줄일 수 있습니다. 이를 통해 토큰이 탈취되었을 때의 심각도를 낮출 수 있습니다.

토큰 페이로드#

각 ID 토큰에는 다음 표준 클레임이 포함됩니다:

필드 설명
iss 토큰 발급자로, GitLab 인스턴스의 도메인입니다("issuer" 클레임).
sub 토큰의 주체입니다("subject" 클레임). 기본값은 project_path:{group}/{project}:ref_type:{type}:ref:{branch_name} 입니다. 프로젝트 API를 사용해 프로젝트 단위로 구성할 수 있습니다. sub 클레임에는 ref_protected 같은 추가 필드와, job 이 환경을 지정한 경우 environment_protected·deployment_tier 같은 환경 관련 필드가 포함될 수 있습니다. GitLab 18.7에서 도입되었습니다.
aud 토큰의 의도된 audience 입니다("audience" 클레임). ID 토큰 구성에서 지정합니다. 기본값은 GitLab 인스턴스의 도메인입니다.
exp 만료 시각입니다("expiration time" 클레임).
nbf 토큰이 유효해지는 시점입니다("not before" 클레임).
iat JWT가 발급된 시각입니다("issued at" 클레임).
jti 토큰의 고유 식별자입니다("JWT ID" 클레임).

토큰에는 GitLab 이 제공하는 커스텀 클레임도 포함됩니다:

필드 시점 설명
project_id 항상 job을 실행하는 프로젝트의 ID입니다. 머지 리퀘스트 파이프라인에서는 소스 프로젝트의 ID입니다.
project_path 항상 job을 실행하는 프로젝트의 경로입니다. 머지 리퀘스트 파이프라인에서는 소스 프로젝트의 경로입니다.
namespace_id 항상 job을 실행하는 프로젝트의 네임스페이스 ID입니다. 머지 리퀘스트 파이프라인에서는 소스 프로젝트의 네임스페이스 ID입니다.
namespace_path 항상 job을 실행하는 프로젝트의 네임스페이스 경로입니다. 머지 리퀘스트 파이프라인에서는 소스 프로젝트의 네임스페이스 경로입니다.
user_id 항상 job을 실행하는 사용자의 ID입니다.
user_login 항상 job을 실행하는 사용자의 사용자 이름입니다.
user_email 항상 job을 실행하는 사용자의 이메일입니다.
user_access_level 항상 job을 실행하는 사용자의 액세스 레벨입니다.
job_project_id 항상 job을 실행하는 프로젝트의 ID입니다. ID 기준으로 프로젝트 범위를 지정할 때 사용합니다. GitLab 18.4에서 도입되었습니다.
job_project_path 항상 job을 실행하는 프로젝트의 경로입니다. 경로 기준으로 프로젝트 범위를 지정할 때 사용합니다. GitLab 18.4에서 도입되었습니다.
job_namespace_id 항상 job을 실행하는 프로젝트의 네임스페이스 ID입니다. ID 기준으로 그룹 또는 사용자 수준 네임스페이스 범위를 지정할 때 사용합니다. GitLab 18.4에서 도입되었습니다.
job_namespace_path 항상 job을 실행하는 프로젝트의 네임스페이스 경로입니다. 경로 기준으로 그룹 또는 사용자 수준 네임스페이스 범위를 지정할 때 사용합니다. GitLab 18.4에서 도입되었습니다.
source_project_id 항상 소스 코드가 있는 프로젝트의 ID입니다. 머지 리퀘스트 파이프라인에서는 머지 리퀘스트의 소스 프로젝트 ID입니다. GitLab 19.5에서 도입되었습니다.
source_project_path 항상 소스 코드가 있는 프로젝트의 경로입니다. 머지 리퀘스트 파이프라인에서는 머지 리퀘스트의 소스 프로젝트 경로입니다. GitLab 19.5에서 도입되었습니다.
source_namespace_id 항상 소스 코드가 있는 프로젝트의 네임스페이스 ID입니다. 머지 리퀘스트 파이프라인에서는 머지 리퀘스트의 소스 프로젝트 네임스페이스 ID입니다. GitLab 19.5에서 도입되었습니다.
source_namespace_path 항상 소스 코드가 있는 프로젝트의 네임스페이스 경로입니다. 머지 리퀘스트 파이프라인에서는 머지 리퀘스트의 소스 프로젝트 네임스페이스 경로입니다. GitLab 19.5에서 도입되었습니다.
user_identities 사용자 환경설정 사용자의 외부 아이덴티티 목록입니다.
pipeline_id 항상 파이프라인의 ID입니다.
pipeline_source 항상 파이프라인 소스입니다.
job_id 항상 job의 ID입니다.
ref 항상 job의 Git ref입니다. 머지 리퀘스트 파이프라인에서는 소스 브랜치의 ref입니다.
ref_type 항상 Git ref 유형으로, branch 또는 tag 입니다.
ref_path 항상 job의 정규화된 ref입니다. 예를 들어 refs/heads/main 입니다. 머지 리퀘스트 파이프라인에서는 소스 브랜치의 ref 경로입니다.
ref_protected 항상 Git ref가 보호된 경우 true, 그렇지 않으면 false 입니다.
groups_direct 사용자가 0~200개 그룹의 직접 멤버인 경우 사용자가 직접 멤버로 속한 그룹의 경로입니다. 사용자가 200개를 초과하는 그룹의 직접 멤버인 경우 생략됩니다. 기능 플래그 ci_jwt_groups_direct가 GitLab 17.3에서 추가되었습니다. 기본적으로 비활성화되어 있습니다.
environment job 이 환경을 지정한 경우 이 job 이 배포하는 환경입니다.
environment_protected job 이 환경을 지정한 경우 배포된 환경이 보호된 경우 true, 그렇지 않으면 false 입니다.
deployment_tier job 이 환경을 지정한 경우 job 이 지정한 환경의 배포 티어입니다.
environment_action job 이 환경을 지정한 경우 job에 지정된 환경 작업(environment:action)입니다.
runner_id 항상 job을 실행하는 러너의 ID입니다.
runner_environment 항상 job에 사용된 러너의 유형입니다. gitlab-hosted 또는 self-hosted 중 하나입니다.
sha 항상 job의 커밋 SHA입니다.
ci_config_ref_uri 항상 최상위 파이프라인 정의의 ref 경로입니다. 예를 들어 gitlab.example.com/my-group/my-project//.gitlab-ci.yml@refs/heads/main 입니다. 파이프라인 정의가 동일한 프로젝트에 있지 않은 경우 이 클레임은 null 입니다.
ci_config_sha 항상 ci_config_ref_uri의 Git 커밋 SHA입니다. 파이프라인 정의가 동일한 프로젝트에 있지 않은 경우 이 클레임은 null 입니다.
project_visibility 항상 파이프라인이 실행 중인 프로젝트의 가시성입니다. internal, private, public 중 하나입니다.
job_source 항상 job 소스입니다. GitLab 18.9에서 도입되었습니다.
job_config job 이 정책에 의해 트리거된 경우 job의 출처에 대한 메타데이터입니다. 정책 job의 경우 정책 구성의 sha와 url을 포함합니다. GitLab 18.9에서 도입되었습니다.
{
  "namespace_id": "72",
  "namespace_path": "my-group",
  "project_id": "20",
  "project_path": "my-group/my-project",
  "user_id": "1",
  "user_login": "sample-user",
  "user_email": "sample-user@example.com",
  "user_identities": [
      {"provider": "github", "extern_uid": "2435223452345"},
      {"provider": "bitbucket", "extern_uid": "john.smith"}
  ],
  "pipeline_id": "574",
  "pipeline_source": "push",
  "job_id": "302",
  "ref": "feature-branch-1",
  "ref_type": "branch",
  "ref_path": "refs/heads/feature-branch-1",
  "ref_protected": "false",
  "groups_direct": ["mygroup/mysubgroup", "myothergroup/myothersubgroup"],
  "environment": "test-environment2",
  "environment_protected": "false",
  "deployment_tier": "testing",
  "environment_action": "start",
  "job_source": "push",
  "job_config": {
    "url": "https://gitlab.example.com/my-group/my-policy-project/-/blob/ab035e64eca9a7a85bd62e485d3593f52a2804ac/.gitlab/security-policies/policy.yml",
    "sha": "ab035e64eca9a7a85bd62e485d3593f52a2804ac"
  },
  "runner_id": 1,
  "runner_environment": "self-hosted",
  "sha": "714a629c0b401fdce83e847fc9589983fc6f46bc",
  "project_visibility": "public",
  "ci_config_ref_uri": "gitlab.example.com/my-group/my-project//.gitlab-ci.yml@refs/heads/main",
  "ci_config_sha": "714a629c0b401fdce83e847fc9589983fc6f46bc",
  "jti": "235b3a54-b797-45c7-ae9a-f72d7bc6ef5b",
  "iss": "https://gitlab.example.com",
  "iat": 1681395193,
  "nbf": 1681395188,
  "exp": 1681398793,
  "sub": "project_path:my-group/my-project:ref_type:branch:ref:feature-branch-1",
  "aud": "https://vault.example.com"
}

ID 토큰은 RS256으로 인코딩되며 전용 개인 키로 서명됩니다. 토큰의 만료 시간은 job의 타임아웃이 지정된 경우 해당 타임아웃으로, 지정되지 않은 경우 5분으로 설정됩니다.

클라우드 트러스트 정책에서 ID 토큰 클레임 사용#

GitLab을 OIDC ID 공급자로 연동(federate)하는 클라우드 공급자는 위 클레임을 트러스트 정책의 조건 키로 검증할 수 있습니다.

트러스트 정책을 작성할 때는 클라우드 공급자와 GitLab 오퍼링이 지원하는 경우, sub 같은 경로 기반 클레임과 함께 namespace_id·project_id 같은 안정적이고 고유한 식별자를 포함합니다. project_id는 전역적으로 고유하며 프로젝트가 존재하는 동안 동일하게 유지됩니다. namespace_id는 프로젝트가 현재 네임스페이스에 머무르는 동안 안정적으로 유지됩니다. 두 식별자 모두 경로와 무관하므로, 이를 포함한 트러스트 정책은 그룹이나 프로젝트 이름 변경 같은 경로 변경의 영향을 받지 않습니다.

GitLab.com의 AWS에서는 gitlab.com OIDC ID 공급자에 대해 다음 GitLab 클레임을 조건 키로 사용할 수 있습니다:

  • namespace_id
  • project_id
  • user_id
  • user_login
  • user_email
  • user_access_level
  • ref_protected
  • pipeline_source

이 조건 키는 gitlab.com OIDC ID 공급자에서만 사용할 수 있습니다. GitLab Self-Managed 나 GitLab Dedicated에서는 사용할 수 없으며, 이 경우 AWS 조건 키로는 sub 클레임만 지원됩니다.

사용자가 user_login 이나 user_email을 변경할 수 있으므로 이를 유일한 조건으로 사용하지 않습니다. 지원되는 클레임의 정확한 목록은 GitLab ID 공급자에 대해 AWS가 게시한 조건 키를 참고해 확인합니다.

sub, namespace_id, project_id를 사용하는 전체 AWS 트러스트 정책 예시는 AWS에서 OpenID Connect 구성을 참고합니다. HashiCorp Vault는 바운드 클레임을 참고합니다.

문제 해결#

400: missing token 상태 코드#

이 오류는 ID 토큰에 필요한 하나 이상의 기본 구성 요소가 누락되었거나 예상대로 구성되지 않았음을 나타냅니다.

문제를 찾으려면 관리자가 인스턴스의 exceptions_json.log에서 실패한 메서드에 대한 자세한 내용을 확인할 수 있습니다.

GitLab::Ci::Jwt::NoSigningKeyError#

exceptions_json.log 파일의 이 오류는 데이터베이스에 서명 키가 없어 토큰을 생성하지 못했기 때문일 가능성이 높습니다. 이 문제인지 확인하려면 인스턴스의 PostgreSQL 터미널에서 다음 쿼리를 실행합니다:

SELECT encrypted_ci_jwt_signing_key FROM application_settings;

반환된 값이 비어 있다면 다음 Rails 스니펫을 사용해 새 키를 생성하고 내부적으로 교체합니다:

  key = OpenSSL::PKey::RSA.new(2048).to_pem

  ApplicationSetting.find_each do |application_setting|
    application_setting.update(ci_jwt_signing_key: key)
  end

401: unauthorized 상태 코드#

이 오류는 인증 요청이 실패했음을 나타냅니다. GitLab 파이프라인에서 외부 서비스로 OpenID Connect(OIDC) 인증을 사용할 때 401 Unauthorized 오류는 다음과 같은 몇 가지 일반적인 이유로 발생할 수 있습니다:

  • ID 토큰 대신 $CI_JOB_JWT_V2 같은 지원 종료된 토큰을 사용했습니다. 자세한 내용은 구버전 JSON Web Token 지원 종료를 참고합니다.
  • .gitlab-ci.yml 파일과 외부 서비스의 OIDC ID 공급자 구성 간에 provider_name 값이 일치하지 않습니다.
  • GitLab 이 발급한 ID 토큰과 외부 서비스가 기대하는 값 사이에 aud(audience) 클레임이 누락되었거나 일치하지 않습니다.
  • GitLab CI/CD job에서 id_tokens: 블록을 활성화하거나 구성하지 않았습니다.

오류를 해결하려면 job 내부에서 토큰을 디코딩합니다:

echo $OIDC_TOKEN | cut -d '.' -f2 | base64 -d | jq .

다음을 확인합니다:

  • aud(audience)가 예상되는 audience(예: 외부 서비스의 URL)와 일치하는지 확인합니다.
  • sub(subject)가 서비스의 ID 공급자 설정에 매핑되어 있는지 확인합니다.
  • GitLab ID 토큰에는 기본적으로 preferred_username 이 포함되지 않는다는 점을 확인합니다.

오류: ID token issuance is disabled#

CI/CD job 이 ID 토큰을 요청할 때 다음 오류가 발생할 수 있습니다:

ID token issuance is disabled in CI because a project path in the `sub` claim was previously used by a different project.

구성된 sub 클레임에 다른 프로젝트가 이전에 사용했던 경로의 project_path, job_project_path 또는 source_project_path가 포함된 경우 GitLab은 ID 토큰 발급을 차단합니다. 이 제한은 새 프로젝트가 이전 프로젝트에 속한 외부 트러스트 정책을 물려받는 것을 방지합니다.

오류를 해결하려면 프로젝트 API를 사용해 ci_id_token_sub_claim_components를 설정하고 첫 번째 값으로 ID 구성 요소를 지정합니다. 사용하던 경로 구성 요소에 대응하는 ID 구성 요소를 사용합니다. project_path에는 project_id, job_project_path에는 job_project_id, source_project_path에는 source_project_id를 사용합니다. 예를 들면 다음과 같습니다.

{
  "ci_id_token_sub_claim_components": ["project_id", "ref_type", "ref"]
}

그 결과 sub 클레임은 다음과 같은 형식을 갖습니다:

project_id:<id>:ref_type:<type>:ref:<ref>

각 외부 서비스의 트러스트 정책을 새 subject에 맞게 업데이트합니다. 경로 이력이 예상과 다르다면 인스턴스 관리자에게 검토를 요청합니다.

클라우드 서비스 트러스트 정책 가이드는 프로젝트 ID를 subject로 사용을 참고합니다.