일단 이 글을 읽는 사람은 github-action으로 aws나 gcp에 배포나 pipeline을 구축해본 경험이 있어야 한다. 그리고 인증과 인가에 대한 기본적인 지식이 있어야 한다 클라우드도 그렇고 git도 그렇고 심지어 쿠버네티스까지 가장 어렵고 난해한 부분 중 하나가 인증이라고 생각한다.
왜 OIDC를 사용 해야 하죠?
그냥 accesskey(aws)나 service account에 key를 발급(gcp)를 사용하면 안되나요?
물론 된다 하지만 이미 밖으로 나간 파일을 100퍼센트 관리를 잘 할 자신 있나? 퇴사자가 파일을 가지고 나가서 헛짓거리를 한다면? 모니터링 할 수 있을까?(물론 할수 있다 하지만 개발하기도 바쁜데 과연 볼수 있을까??) 특히 사용자 계정과 서비스 계정이 분리 된 상태에서 이 키를 가지고 있는 사람이 퇴사를 할 경우 그 사람의 서비스 계정은 삭제 하더라도 키가 남아 있기 때문에 악의적인 사용자가 키를 가지고 무언가를 할 수 있다.
그럼 access key(aws)나 service account(gcp)를 github secret에 저장 해놓고 쓰면 안되나요?
이것도 물론 된다. 이 질문을 한 사람은 적어도 중급 레벨 정도는 되는 사람이다. 그럼에도 불구하고 이 방법도 결국 키를 숨겨 놨을 뿐이지 키를 결국 밖으로 내보내는 것이다.
일단 그 전에 하나만 더 생각을 해보자 key를 잘 관리 할 수 있는 방법은 무엇이 있을까?
본인 피셜 키를 제일 잘 관리 하는 방법은 아예 키를 안만드는 것이다
그럼 어쩌라는거죠?
그래서 지금 부터 그 방법을 알려주려 한다. 그것이 바로 key발급이 필요 없는 oidc와 oauth를 사용하는 것이다.
아니 key 발급을 안했는데 내가 누구인줄 알고 AWS나 GCP에서 접근을 허용 해주나요?
당연히 아무나 들어오는 것은 안된다. 하지만 GCP의 OIDC(워크로드 ID라고 GCP는 표현을 하고 있다.) 그리고 GCP나 이 것을 셋팅한 사람은 이미 들어와야 할 대상에 대한 설정(조건)을 이미 정해 놓은 상태 이기 때문에 사전에 명단을 작성한 id 나 object들은 인증이 이미 준비 되어 있다고 봐야 할 것이다.
조금 더 쉽게 생각 해보면 집에 들어가는 방법이 열쇠만 있는것이 아니고 지문이나 동공인식 등등 여러가지 방법이 있는 것으로 생각해보면 될것 같다. 그냥 oidc는 지문 사전 등록 이라고 생각하자
그럼 이야기만 들어보면 oidc 나 oauth , SSO등을 이용 하면 좋은데 왜 키를 많이 쓰나요?
당연히 키를 발급하는것보다는 무조건 좋다. 하지만 아직 모든 서비스가 이를 지원하지 않는다. 그리고 이 시스템을 도입하는 것은 러닝 커브가 있기 때문에 조금 어렵다. 그렇지만 개념을 알고 있다면 대부분의 시스템이 많이 지원을 하고 있기 때문에 다방면으로 쓰일 수 있을 것이다.
Work Flow
무엇을 해볼 것인가?
먼저 git branch에 push를 하면 간단하게 gcloud의 명령어를 실행 해보는 간단한 실습을 진행 할 것이다. 당연한 이야기지만 gcloud cli에서 명령어를 실행 하려면 적절한 인증과 인가가 필요하다.
도입하기로 마음 먹었다면 해야 할 작업은 크게 두가지 이다.
GCP에서 작업
GITHUB에서 작업
Service Flow Chart
작업 순서
Google Cloud 워크로드 ID 공급자 추가
콘솔에서 생성
새 ID 풀 만들기
매핑을 구성하고 조건을 추가합니다.
서비스 계정에 새 풀을 연결합니다.
하지만 나는 gcloud cli로 진행 하였다.
# TODO: replace ${PROJECT_ID} with your value below.
#{PROJECT_ID} 는 GCP 프로젝트 ID
gcloud iam workload-identity-pools create "github" \
--project="${PROJECT_ID}" \
--location="global" \
--display-name="GitHub Actions Pool"
결과
공급업체(Provider) 생성
# TODO: replace ${PROJECT_ID} and ${GITHUB_ORG} with your values below.
#{PROJECT_ID} 는 GCP 프로젝트 ID
#{GITHUB_ORG} 는 깃허브 조직의 소유자 이름 으로 알맞게 변형해주거나 환경 변수를 넣어주면 된다
# 참고로 내 ID는 export GITHUB_ORG=kimutae1
gcloud iam workload-identity-pools providers create-oidc "latimi" \
--project="${PROJECT_ID}" \
--location="global" \
--workload-identity-pool="github" \
--display-name="latimi org repo Provider" \
--attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository,attribute.repository_owner=assertion.repository_owner" \
--attribute-condition="assertion.repository_owner == '${GITHUB_ORG}'" \
--issuer-uri="https://token.actions.githubusercontent.com"
완성 되면 우측에 공급업체가 생성된다.
상세 페이지에서 확인 할 수 있다
이 부분은 처음엔 조금 어려웠는데 예제를 보면서 이해를 하니 쉽게 이해 할 수 있었다. 여기서부터 중요하다 집중하자! 처음에는 아래와 같이 생성 되었을 것이다.
assertion.repository_owner == 'kimutae1'
repo의 주인이 kimutae1 일 경우만 인증이 된다는 뜻이다.
이렇게 셋팅하면 오너 인증 밖에 안되서 여러가지 조건을 조합 해보고 싶었다. 문법은 공부를 해야 하지만 가장 간단하게 사용 할 수 있는 and 와 or 연산자 정도 알면 바로 이용 할 수 있다.
아래 링크를 통해 확인 하자
그리고 조건에 따른 변수를 지정 해야 하는데 그것은 토큰을 내용을 살펴보면 알수 있다. jwt 토큰은 아래와 같은 모양으로 되어 있는데 많은 변수들을 지원하고 있어 내가 원하는 값을 변수로 지정하고 가져오기만 하면 된다!
그리고 당연한 이야기지만 저 서비스 어카운트도 사전에 만들어 놔야 하고 진행 하려는 동작에 맞는 적당한 role이 미리 부여 되었는지 확인 해야 한다. 이걸 모른다면 아직은 이 글을 봐도 크게 의미가 없을 수도 있다. role을 만들고 활용 할 수 있도록 인증과 인가에 대해서 좀 더 공부를 하도록 하자
github action 에서 사용하기
이제 거의 다 왔다 위에 셋팅을 끝냈다면 이제 git-action에서 사용 할 수 있는 상태가 되었다. 바로 셋팅 해보자
먼저 위의 조건이 2가지 이기 때문에 github repo를 두개를 셋팅 해봤다.
repo-owner:kimutae1 라면 아무 repo에서 실행 해도 성공 해야 한다.
repo:latimi/cicd 에서 git-action을 실행 하면 누가 구동 하던지 성공 해야 한다.
Workload Identity Federation through a Service Account
아래 처럼 cicd.yaml을 생성 한뒤 .github/workflows/ 에 넣어준다. ${PROJECT_ID} 는 프로젝트 ID를 넣어주면 된다.
name: GCP 서비스 목록 조회
on:
push:
branches:
- main
permissions:
contents: 'read'
id-token: 'write'
jobs:
list-gcp-services:
runs-on: ubuntu-latest
steps:
- name: 'GCP 인증'
id: 'auth'
uses: 'google-github-actions/auth@v2'
with:
workload_identity_provider: 'projects/${PROJECT_ID}/locations/global/workloadIdentityPools/github/providers/latimi2'
service_account: 'kth-sa@storied-imprint-408506.iam.gserviceaccount.com'
- name: 'GCP 서비스 목록 조회'
run: |
gcloud services list