DevOps
  • Introduction
  • Setting
    • Terminal
      • Tmux
    • WSL+Ubuntu
    • [NeoVIM]
      • install & 활용방법
      • error 처리
      • LazyVIM
        • install & 활용방법
    • ssh
    • mysql
    • package관리
  • Fundamental(basic)
    • Network
      • https
  • [GitOps]
    • [SCM]
      • [Github]
        • center-managed
      • bitbucket
      • AWS-codeCommit
  • roadmap
    • devops
    • kubernetes
    • AWS
    • MLOPS
  • Cloud
    • [AWS]
      • aws sso script
      • tagging 자동화
      • 동일cidr에서 VPC 연결
      • 무중단서비스를 위한 고려사항
    • [GCP]
      • [GCP] GCP의 VPC
      • [GCP] GCP의 ALB
      • [GCP] OIDC와 OAUTH를 활용한 github action
      • [GCP] Composer 설명
      • [GCP] gmail-api
      • [GCP] DataLake
      • [GCP] Cloud 관리형 계정&role
      • [[GCP] private환경
        • DNS 설정으로 google api 및 colab-notebook 사용 하기
        • intelligence 설정으로 google api 및 colab-notebook 사용 하기
  • [kubernetes]
    • [cloud 기반]
      • csr
  • InfraAsCode
    • terraform
  • 코드로 그리는 다이어그램
    • CodeAsDiagram
      • example
    • Mermaid
    • PDFtoImage
  • AutoMation
  • [ETC]
    • Magic_Trackpad Window설치
Powered by GitBook
On this page
  • GITHUB action과 GCP OIDC 연동
  • Introduction
  • Work Flow
  • 작업 순서
  • Google Cloud 워크로드 ID 공급자 추가
  • 결과
  • 공급업체(Provider) 생성
  • 서비스 계정에 풀 연결
  • github action 에서 사용하기
  • Workload Identity Federation through a Service Account
  1. Cloud
  2. [GCP]

[GCP] OIDC와 OAUTH를 활용한 github action

GITHUB action과 GCP OIDC 연동


Introduction

이 글을 읽는 사람

일단 이 글을 읽는 사람은 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에서 명령어를 실행 하려면 적절한 인증과 인가가 필요하다.

도입하기로 마음 먹었다면 해야 할 작업은 크게 두가지 이다.

  1. GCP에서 작업

  2. GITHUB에서 작업


Service Flow Chart


작업 순서

Google Cloud 워크로드 ID 공급자 추가

콘솔에서 생성

  1. 새 ID 풀 만들기

  2. 매핑을 구성하고 조건을 추가합니다.

  3. 서비스 계정에 새 풀을 연결합니다.

사용할 발급자 URL: https://token.actions.githubusercontent.com

하지만 나는 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 연산자 정도 알면 바로 이용 할 수 있다.

아래 링크를 통해 확인 하자

cel문법

그리고 조건에 따른 변수를 지정 해야 하는데 그것은 토큰을 내용을 살펴보면 알수 있다. jwt 토큰은 아래와 같은 모양으로 되어 있는데 많은 변수들을 지원하고 있어 내가 원하는 값을 변수로 지정하고 가져오기만 하면 된다!

jwt yaml

{
  "typ": "JWT",
  "alg": "RS256",
  "x5t": "example-thumbprint",
  "kid": "example-key-id"
}
{
  "jti": "example-id",
  "sub": "repo:octo-org/octo-repo:environment:prod",
  "aud": "https://github.com/octo-org",
  "ref": "refs/heads/main",
  "sha": "example-sha",
  "repository": "octo-org/octo-repo",
  "repository_owner": "octo-org",
  "actor_id": "12",
  "repository_id": "74",
  "repository_owner_id": "65",
  "run_id": "example-run-id",
  "run_number": "10",
  "run_attempt": "2",
  "actor": "octocat",
  "workflow": "example-workflow",
  "head_ref": "",
  "base_ref": "",
  "event_name": "workflow_dispatch",
  "ref_type": "branch",
  "job_workflow_ref": "octo-org/octo-automation/.github/workflows/oidc.yml@refs/heads/main",
  "iss": "https://token.actions.githubusercontent.com",
  "nbf": 1632492967,
  "exp": 1632493867,
  "iat": 1632493567
}

[link] (https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/using-openid-connect-with-reusable-workflows)

클릭하여 펼치기

assertion.repository_owner == 'kimutae1' || assertion.repository == 'latimi/cicd'

이렇게 셋팅 할 경우 두가지 조건 중 하나라도 만족하게 되면 일단 프로바이더 인증이 된다

  1. repository_owner가 kimutae1 이거나

  2. repository가 latimi/cicd 이거나

여기까지 셋팅이 되었다면 인증과 인가 중에 인증 부분은 끝난 것이다.


서비스 계정에 풀 연결

이제 내가 누구인지는 증명을 하였으니 이제 내가 무엇을 할 수 있는지를 설정 해줘야 한다. 풀 메뉴에서 +엑세스 권한 부여를 눌러보자

그럼 아래와 같이 나올 것이다.

제휴 ID를 사용하여 권한 부여는 뭔가 좀 복잡해 보여서 서비스 계정 가장으로 진행 하려 한다. 서비스 계정 가장이라는데 말이 좀 웃기긴 한데 맞는 말이다. (Grant access using Service Account impersonation)

  • 보통 권한 위임이라는 말을 많이 쓰지 않나..어쨋든

여기서 위의 프로바이더에서 조건 설정을 잘했다면 주 구성원에 속성이 잘 보일 것이다.

아래 처럼 될수 있게 두번 작업하자

 attribute.repository="latimi/cicd" 
 attribute.repository_owner="kimutae1"

그리고 당연한 이야기지만 저 서비스 어카운트도 사전에 만들어 놔야 하고 진행 하려는 동작에 맞는 적당한 role이 미리 부여 되었는지 확인 해야 한다. 이걸 모른다면 아직은 이 글을 봐도 크게 의미가 없을 수도 있다. role을 만들고 활용 할 수 있도록 인증과 인가에 대해서 좀 더 공부를 하도록 하자

github action 에서 사용하기

이제 거의 다 왔다 위에 셋팅을 끝냈다면 이제 git-action에서 사용 할 수 있는 상태가 되었다. 바로 셋팅 해보자

먼저 위의 조건이 2가지 이기 때문에 github repo를 두개를 셋팅 해봤다.

  1. repo-owner:kimutae1 라면 아무 repo에서 실행 해도 성공 해야 한다.

  2. 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

이제 push를 하고 git-action로그를 좀 보자

GCP 서비스 목록 조회가 잘 되었다.

파고들기

aud의 의미를 잘 몰라서 git action 내에서 직접 json파일을 뒤져봤다.


  shell: /usr/bin/bash -e {0}
  env:
    CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE: /home/runner/work/gcp-gitaction-oidc/gcp-gitaction-oidc/gha-creds-0c2f4ef3ca784aca.json
    GOOGLE_APPLICATION_CREDENTIALS: /home/runner/work/gcp-gitaction-oidc/gcp-gitaction-oidc/gha-creds-0c2f4ef3ca784aca.json
    GOOGLE_GHA_CREDS_PATH: /home/runner/work/gcp-gitaction-oidc/gcp-gitaction-oidc/gha-creds-0c2f4ef3ca784aca.json
    CLOUDSDK_CORE_PROJECT: storied-imprint-408506
    CLOUDSDK_PROJECT: storied-imprint-408506
    GCLOUD_PROJECT: storied-imprint-408506
    GCP_PROJECT: storied-imprint-408506
    GOOGLE_CLOUD_PROJECT: storied-imprint-408506
------------------------------------------------
cat ${GOOGLE_APPLICATION_CREDENTIALS}

{"type":"external_account","audience":"//iam.googleapis.com/projects/132409220076/locations/global/workloadIdentityPools/github/providers/latimi2","subject_token_type":"urn:ietf:params:oauth:token-type:jwt","token_url":"https://sts.googleapis.com/v1/token","credential_source":{"url":"https://pipelinesghubeus6.actions.githubusercontent.com/aYuIYwdO1bDxphT894ABFpomrSDmJThF159HSsrMxCBAeUUiRG/00000000-0000-0000-0000-000000000000/_apis/distributedtask/hubs/Actions/plans/03de2929-0ca7-4444-8e31-331b8c01b272/jobs/80f6d6fd-1976-5e3f-858e-43d998664dd7/idtoken?api-version=2.0&audience=https%3A%2F%2Fiam.googleapis.com%2Fprojects%2F132409220076%2Flocations%2Fglobal%2FworkloadIdentityPools%2Fgithub%2Fproviders%2Flatimi2","headers":{"Authorization":"***"},"format":{"type":"json","subject_token_field_name":"value"}},"service_account_impersonation_url":"https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/kth-sa@storied-imprint-408506.iam.gserviceaccount.com:generateAccessToken"}
---------------------------------------------------------------------------------

cat ${CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE}

{"type":"external_account","audience":"//iam.googleapis.com/projects/132409220076/locations/global/workloadIdentityPools/github/providers/latimi2","subject_token_type":"urn:ietf:params:oauth:token-type:jwt","token_url":"https://sts.googleapis.com/v1/token","credential_source":{"url":"https://pipelinesghubeus6.actions.githubusercontent.com/aYuIYwdO1bDxphT894ABFpomrSDmJThF159HSsrMxCBAeUUiRG/00000000-0000-0000-0000-000000000000/_apis/distributedtask/hubs/Actions/plans/03de2929-0ca7-4444-8e31-331b8c01b272/jobs/80f6d6fd-1976-5e3f-858e-43d998664dd7/idtoken?api-version=2.0&audience=https%3A%2F%2Fiam.googleapis.com%2Fprojects%2F132409220076%2Flocations%2Fglobal%2FworkloadIdentityPools%2Fgithub%2Fproviders%2Flatimi2","headers":{"Authorization":"***"},"format":{"type":"json","subject_token_field_name":"value"}},"service_account_impersonation_url":"https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/kth-sa@storied-imprint-408506.iam.gserviceaccount.com:generateAccessToken"}
---------------------------------------------------------------------------------

cat ${GOOGLE_GHA_CREDS_PATH}

{"type":"external_account","audience":"//iam.googleapis.com/projects/132409220076/locations/global/workloadIdentityPools/github/providers/latimi2","subject_token_type":"urn:ietf:params:oauth:token-type:jwt","token_url":"https://sts.googleapis.com/v1/token","credential_source":{"url":"https://pipelinesghubeus6.actions.githubusercontent.com/aYuIYwdO1bDxphT894ABFpomrSDmJThF159HSsrMxCBAeUUiRG/00000000-0000-0000-0000-000000000000/_apis/distributedtask/hubs/Actions/plans/03de2929-0ca7-4444-8e31-331b8c01b272/jobs/80f6d6fd-1976-5e3f-858e-43d998664dd7/idtoken?api-version=2.0&audience=https%3A%2F%2Fiam.googleapis.com%2Fprojects%2F132409220076%2Flocations%2Fglobal%2FworkloadIdentityPools%2Fgithub%2Fproviders%2Flatimi2","headers":{"Authorization":"***"},"format":{"type":"json","subject_token_field_name":"value"}},"service_account_impersonation_url":"https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/kth-sa@storied-imprint-408506.iam.gserviceaccount.com:generateAccessToken"}

이로써 당신은 key 발급 없이 인증 및 인가를 받았다

GCP가 망하기 전까지 한번 설정을 해놓으면 자손 대대로 잘 사용 할 수 있을 것이다. 그리고 조건을 조금 더 유연하게 혹은 견고 하게 설정한다면 많은 변경 사항 없이 보안과 편의성을 챙길 수가 있을 것이다.

참고 링크 gcp workload identity github oidc

Previous[GCP] GCP의 ALBNext[GCP] Composer 설명

Last updated 7 months ago

인증은 api 와 jwt token으로 이루어진다.
alt text
alt text
alt text
alt text
alt text
alt text
alt text
alt text
alt text
alt text