GCP Workload Identity Federation으로 OpenID Connect 구성하기
GCP Workload Identity Federation으로 OpenID Connect 구성하기
GitLab CI/CD job에서 JWT 토큰과 Workload Identity Federation을 사용해 Google Cloud에 인증하는 방법을 함께 알아볼게요. 이 구성은 비밀을 전혀 저장하지 않고도 요청 시 단기 자격 증명을 생성합니다. GitLab과 Google Cloud 사이의 ID 페더레이션을 위해 OpenID Connect (OIDC)를 구성하는 것으로 시작해요.
출처: 문서
본문
- 티어(Tier): Free, Premium, Ultimate
- 제공 방식(Offering): GitLab.com, GitLab Self-Managed, GitLab Dedicated
CI_JOB_JWT_V2는 GitLab 17.0에서 제거되었어요. 대신 ID 토큰을 사용하세요.
GitLab과 함께 OIDC를 사용하는 방법에 대한 자세한 내용은 클라우드 서비스 연결하기를 읽어보세요.
이 튜토리얼은 Google Cloud 계정과 Google Cloud 프로젝트가 있다고 가정해요. 계정에는 Google Cloud 프로젝트에 대해 최소 workload identity pool Admin 권한이 있어야 합니다.
이 튜토리얼 대신 Terraform 모듈과 CI/CD 템플릿을 선호한다면 OIDC가 GitLab CI/CD 파이프라인의 Google Cloud 인증을 어떻게 단순화하는지를 참고하세요.
이 튜토리얼을 완료하려면:
- Google Cloud workload identity pool 만들기.
- workload identity provider 만들기.
- 서비스 계정 가장(impersonation) 권한 부여하기.
- 임시 자격 증명 가져오기.
Google Cloud workload identity pool 만들기
다음 옵션으로 새 Google Cloud workload identity pool을 만들어요:
- Name:
GitLab같은 사람이 읽기 좋은 workload identity pool 이름. - Pool ID:
gitlab같은, Google Cloud 프로젝트에서 workload identity pool의 고유 ID. 이 값은 pool을 참조하는 데 사용되고 URL에 나타나요. - Description: 선택 사항. pool에 대한 설명.
- Enabled Pool: 이 옵션이
true인지 확인해요.
Google Cloud 프로젝트당 GitLab 설치당 pool 하나를 만들어요. 같은 GitLab 인스턴스에 여러 리포지토리와 CI/CD job이 있다면, 같은 pool에 대해 서로 다른 provider로 인증할 수 있습니다.
workload identity provider 만들기
이전 단계에서 만든 workload identity pool 안에, 다음 옵션으로 새 Google Cloud workload identity provider를 만들어요:
- Provider type: OpenID Connect (OIDC).
- Provider name:
gitlab/gitlab같은, workload identity provider의 사람이 읽기 좋은 이름. - Provider ID:
gitlab-gitlab같은, pool 안에서 workload identity provider의 고유 ID. 이 값은 provider를 참조하는 데 사용되고 URL에 나타나요. - Issuer (URL): GitLab 인스턴스 주소(예:
https://gitlab.com/또는https://gitlab.example.com/). - 주소는https://프로토콜을 사용해야 해요. - 주소는 마지막 슬래시로 끝나야 해요. - Audiences: 허용된 audiences 목록을 GitLab 인스턴스 주소로 수동 설정(예:
https://gitlab.com또는https://gitlab.example.com). - 주소는https://프로토콜을 사용해야 해요. - 주소는 마지막 슬래시로 끝나면 안 돼요. - Provider attributes mapping: 다음 매핑을 만들어요. 여기서
attribute.X는 Google 토큰에 클레임으로 포함될 속성 이름이고,assertion.X는 GitLab 클레임에서 추출할 값이에요: | 속성 (Google) | 어서션 (GitLab) | | --- | --- | |google.subject|assertion.sub| |attribute.X|assertion.X| Common Expression Language (CEL)로 복잡한 속성을 만들 수도 있어요. 권한 부여에 사용하려는 모든 속성을 매핑해야 해요. 예를 들어 다음 단계에서 사용자의 이메일 주소를 기준으로 권한을 매핑하려면attribute.user_email을assertion.user_email에 매핑해야 합니다.
GitLab.com에 호스팅된 프로젝트의 경우, GCP는 접근을 GitLab 그룹이 발급한 토큰으로만 제한할 것을 요구해요.
서비스 계정 가장(impersonation) 권한 부여하기
workload identity pool과 workload identity provider를 만드는 것은 Google Cloud로의 인증을 정의해요. 이 시점에서 GitLab CI/CD job은 Google Cloud에 인증할 수 있습니다. 하지만 Google Cloud에서 어떤 권한도(승인 authorization) 갖고 있지 않아요.
GitLab CI/CD job에 Google Cloud 권한을 부여하려면:
- Google Cloud Service Account를 만들어요. 원하는 이름과 ID를 사용할 수 있어요.
- Google Cloud 리소스에서 서비스 계정에 IAM 권한을 부여해요. 이 권한은 사용 사례에 따라 크게 달라집니다. 일반적으로 GitLab CI/CD job이 사용하기를 원하는 Google Cloud 프로젝트와 리소스에 대한 권한을 이 서비스 계정에 부여해요. 예를 들어 GitLab CI/CD job에서 Google Cloud Storage 버킷에 파일을 업로드해야 한다면, Cloud Storage 버킷에 이 Service Account에
roles/storage.objectCreator역할을 부여하면 됩니다. - 외부 ID 권한을 부여해 그 Service Account를 가장(impersonate)하게 해요. 이 단계는 GitLab CI/CD job이 Service Account 가장을 사용해 Google Cloud에 권한을 부여할 수 있게 합니다. 이 단계는 Service Account 자체에 IAM 권한을 부여해서, 외부 ID가 그 서비스 계정으로 행동할 수 있는 권한을 주는 거예요. 외부 ID는
principalSet://프로토콜로 표현됩니다.
이전 단계와 마찬가지로 이 단계도 원하는 구성에 크게 의존해요. 예를 들어 사용자 이름이 chris인 GitLab 사용자가 시작한 GitLab CI/CD job이 my-service-account라는 Service Account를 가장할 수 있게 하려면 my-service-account에 외부 ID에게 roles/iam.workloadIdentityUser IAM 역할을 부여하면 됩니다. 외부 ID 형식은 다음과 같아요:
principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/attribute.user_login/chris
여기서 PROJECT_NUMBER는 Google Cloud 프로젝트 번호이고, POOL_ID는 첫 번째 섹션에서 만든 workload identity pool의 ID(이름 아님)입니다.
이 구성은 이전 섹션의 어서션에서 매핑된 user_login 속성을 추가했다고도 가정해요.
임시 자격 증명 가져오기
OIDC와 역할을 구성한 뒤에는 GitLab CI/CD job이 Google Cloud Security Token Service (STS)에서 임시 자격 증명을 가져올 수 있어요.
CI/CD job에 id_tokens을 추가해요:
job:
id_tokens:
GITLAB_OIDC_TOKEN:
aud: https://gitlab.example.com
ID 토큰으로 임시 자격 증명을 가져와요:
PAYLOAD="$(cat <<EOF
{
"audience": "//iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID",
"grantType": "urn:ietf:params:oauth:grant-type:token-exchange",
"requestedTokenType": "urn:ietf:params:oauth:token-type:access_token",
"scope": "https://www.googleapis.com/auth/cloud-platform",
"subjectTokenType": "urn:ietf:params:oauth:token-type:jwt",
"subjectToken": "${GITLAB_OIDC_TOKEN}"
}
EOF
)"
FEDERATED_TOKEN="$(curl --fail "https://sts.googleapis.com/v1/token" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--data "${PAYLOAD}" \
| jq -r '.access_token'
)"
여기서:
PROJECT_NUMBER는 Google Cloud 프로젝트 번호(이름 아님).POOL_ID는 첫 번째 섹션에서 만든 workload identity pool의 ID.PROVIDER_ID는 두 번째 섹션에서 만든 workload identity provider의 ID.GITLAB_OIDC_TOKEN은 OIDC ID 토큰.
그런 다음 결과 페더레이션 토큰으로 이전 섹션에서 만든 서비스 계정을 가장할 수 있어요:
ACCESS_TOKEN="$(curl --fail "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/SERVICE_ACCOUNT_EMAIL:generateAccessToken" \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer ***" \
--data '{"scope": ["https://www.googleapis.com/auth/cloud-platform"]}' \
| jq -r '.accessToken'
)"
여기서:
SERVICE_ACCOUNT_EMAIL은 이전 섹션에서 만든, 가장할 서비스 계정의 전체 이메일 주소.FEDERATED_TOKEN은 이전 단계에서 가져온 페더레이션 토큰.
결과는 Google Cloud OAuth 2.0 access token으로, bearer 토큰으로 사용하면 대부분의 Google Cloud API와 서비스에 인증할 수 있어요. 이 값을 환경 변수 CLOUDSDK_AUTH_ACCESS_TOKEN으로 설정하면 gcloud CLI에도 전달할 수 있습니다.
동작 예시
이 참조 프로젝트를 검토해서 Terraform으로 GCP에서 OIDC를 프로비저닝하고 임시 자격 증명을 가져오는 샘플 스크립트를 확인해 보세요.
문제 해결 (Troubleshooting)
curl응답을 디버깅할 때는 최신 curl을 설치해요.-f대신--fail-with-body를 사용하세요. 이 명령은 전체 본문을 출력하는데, 유용한 오류 메시지가 담겨 있을 수 있어요.- 자세한 내용은 Workload Identity Federation 문제 해결을 참고하세요.