IaC/CI CD Tool

7. Github Action Build and Push(with GCP Artifact Registry)

Somaz 2024. 6. 19. 17:15
728x90
반응형

Overview

Github Action을 사용해서 Build 후 GCP Artifact Registry에 업로드 하는 방법에 대해서 알아본다.

 


Github Action Build and Push(with GCP Artifact Registry)

 

Github 에서 GCP 인증에 사용할 Service Account를 생성 후 Workload-identity-federation을 구성

 

Workload-identity-federation이란?

Google Cloud Platform (GCP)의 Workload Identity Federation은 external ID providers를 사용하여 Google Cloud 리소스에 접근 권한을 부여하는 기능이다. 이 기능을 사용하면 AWS, Azure, 혹은 어떤 OpenID Connect(OIDC) 호환 ID 제공자를 사용하는 조직도 GCP 서비스에 안전하게 액세스할 수 있다.

  • 멀티 클라우드 보안: Workload Identity Federation을 사용하면 사용자는 Google Cloud 리소스에 접근하기 위해 다른 클라우드 플랫폼의 인증 정보를 활용할 수 있다. 이는 멀티 클라우드 환경에서의 관리와 보안을 강화한다.
  • 안전한 액세스 관리: GCP의 IAM(Identity and Access Management) 정책을 사용하여 외부 시스템의 사용자에게 세밀한 액세스 제어를 제공할 수 있다. 이로 인해 보안이 강화된다.
  • 토큰 교환 및 갱신 자동화: Workload Identity Federation을 통해 외부 ID 제공자에서 Google Cloud로의 토큰 교환 및 갱신이 자동화되어, 사용자가 수동으로 크리덴셜을 관리할 필요가 없어진다.
  • 보다 간편한 통합: 외부 시스템과의 통합이 간소화되며, 이는 특히 다양한 클라우드 환경에서 작업하는 기업에 유용하다.

 

테라폼을 사용해서 구성해준다.

## Service Account ##
module "service_accounts" {
  source       = "../../modules/service_accounts"
  project_id   = var.project
  names        = ["github-action"]
  display_name = "github-action"
  description  = "github-action admin"
}

## Workload Identity Federation ##

data "google_service_account" "github-action" {
  account_id = "github-action"

  depends_on = [module.service_accounts]
}

module "workload_identity_federation" {
  source      = "../../modules/workload_identity_federation"
  project_id  = var.project
  pool_id     = "pool-github-action"
  provider_id = "provider-github-action"

  attribute_mapping = {
    "google.subject"       = "assertion.sub"
    "attribute.actor"      = "assertion.actor"
    "attribute.aud"        = "assertion.aud"
    "attribute.repository" = "assertion.repository"
  }
  issuer_uri = "<https://token.actions.githubusercontent.com>"

  service_accounts = [
    {
      name           = data.google_service_account.github-action.name
      attribute      = "attribute.repository/somaz94/*" # attribute.repository/github repository/*
      all_identities = true
    },
    {
      name           = data.google_service_account.github-action.name
      attribute      = "attribute.repository/somaz94-2/*"
      all_identities = true
    }
  ]
}

 

 

Console에서 아래와 같이 확인가능하다.

 

 

 

 

아래와 같이 권한을 부여하였다.

 

 

 

Github Action Workflow 구성

간단하게 Build Workflow를 구성해본다.

  • Configure GCP credentials 부분에서 `secrets.GCP_WORKLOAD_IDENTITY_PROVIDER` 값으로는 `projects/${project_id}/locations/global/workloadIdentityPools/pool-github-action/providers/provider-github-action 를 secret` 으로 저장해준다.
  • `secrets.GCP_SERVICE_ACCOUNT` 값으로는 `github-action@${project_id}.iam.gserviceaccount.com` 를 secret으로 저장해준다.
name: 1.Build

on:
  push:
    branches:
      # - dev
      - '*'
      - '!main'
      - 'release/*'
    paths:
      - apps/game/**
    
  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:
    inputs:
      environment:
        type: environment
        description: Select the environment
        required: true
      service:
        description: Which service to be built. game or admin or etc...
        required: true
        type: choice
        options:
          - game
  workflow_call:
    inputs:
      branch:
        description: Source branch name
        required: true
        type: string
      environment:
        description: Target environment
        required: true
        type: string
      service:
        description: Service to be built. game or admin or etc...
        required: true
        type: string

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  build:
    name: Build Image
    runs-on: ubuntu-20.04
    env:
      PROJECT: somaz
      SERVICE: ${{ github.event.inputs.service || inputs.service }}
      ENVIRONMENT: ${{ github.event.inputs.environment || inputs.environment }}
    # Add "id-token" with the intended permissions.
    permissions:
      contents: read
      id-token: write

    steps:
      - name: Check out branch for workflow call
        id: checkout-for-workflow-call
        if: ${{ inputs.branch }}
        uses: actions/checkout@v4
        with:
          ref: ${{ inputs.branch }}

      - name: Check out branch for workflow dispatch
        if: ${{ steps.checkout-for-workflow-call.outcome == 'skipped' }}
        uses: actions/checkout@v4

      - name: Set GCP region JP for prod environment
        if: ${{ env.ENVIRONMENT == 'stage' || env.ENVIRONMENT == 'prod' }}
        id: set-prod-region
        run: |
          echo "GCP_REGION=asia-northeast1" >> $GITHUB_ENV

      - name: Set GCP region KR
        if: ${{ steps.set-prod-region.outcome == 'skipped' }}
        run: |
          echo "GCP_REGION=asia-northeast3" >> $GITHUB_ENV

      - name: Extract most recent environment from the last 50 commits
        if: github.event_name == 'push' 
        run: |
          git log -50 --pretty=%B
          COMMIT_MESSAGES=$(git log -50 --pretty=%B)
          ENVIRONMENT=$(echo "$COMMIT_MESSAGES" | grep -oP 'server\\(\\K[^)]*' | head -1 | sed 's/gcp_//')
          echo "ENVIRONMENT=$ENVIRONMENT" >> $GITHUB_ENV

      - name: Use input environment if provided
        if: github.event_name == 'workflow_dispatch' && inputs.environment
        run: |
          echo "ENVIRONMENT=${{ inputs.environment }}" >> $GITHUB_ENV

      - name: Use Default Service Name if push event
        if: github.event_name == 'push' 
        run: |
          echo "SERVICE=${{ inputs.service || 'game' }}" >> $GITHUB_ENV

      - name: Setup environment
        id: env_output
        run: |
          echo "Environment set to: ${{ env.ENVIRONMENT }}"
          echo "Service set to: ${{ env.SERVICE }}"

      - name: Configure GCP credentials
        id: auth         
        uses: google-github-actions/auth@v2
        with:
          token_format: access_token
          workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}
          service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }}
          access_token_lifetime: 500s     

      - name: Set up Cloud SDK
        uses: google-github-actions/setup-gcloud@v2

      - name: Login to Artifact Registry
        id : artifact
        uses: docker/login-action@v3
        with:
          registry: ${{ env.GCP_REGION }}-docker.pkg.dev
          username: oauth2accesstoken
          password: ${{ steps.auth.outputs.access_token }}

      - name: Set short sha
        id: vars
        run: |
          echo "short_sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Build, tag, and push image to GCP Artifact Registry
        uses: docker/build-push-action@v5
        env:
          GCP_SOMAZ_MGMT_PROJECT: ${{ secrets.GCP_SOMAZ_MGMT_PROJECT }}
          GAR_REGISTRY: ${{ env.GCP_REGION }}-docker.pkg.dev
          # SERVICE_NAME: ${{ inputs.service }}
          SERVICE_NAME: ${{ env.SERVICE }}
          GAR_REPOSITORY: ${{ env.PROJECT }}
          IMAGE_TAG: ${{ steps.vars.outputs.short_sha }}
        with:
          context: .
          file: ${{ env.SERVICE_NAME }}.Dockerfile
          push: true
          tags: ${{ env.GAR_REGISTRY }}/${{ env.GCP_SOMAZ_MGMT_PROJECT }}/${{ env.SERVICE }}-${{ env.PROJECT }}/${{ env.SERVICE }}-${{ env.PROJECT }}:${{ steps.vars.outputs.short_sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: Set branch var for workflow_dispatch
        if: github.event_name == 'workflow_dispatch'
        run: |
          echo "IS_BUILD_TRIGGERED_BY_WORKFLOW_DISPATCH=true" >> $GITHUB_ENV

      - name: Outputs build results
        run: |
          echo "target service: ${{ env.SERVICE }}"
          echo "resource branch for workflow dispatch: ${{ github.ref_name }}"
          echo "resource branch for workflow call: ${{ inputs.branch }}"
          echo "deploy environment: ${{ env.ENVIRONMENT }}"
          echo "gar region: ${{ env.GCP_REGION }}"
          echo "image tags: ${{ steps.vars.outputs.short_sha }}"

    outputs:
      tag: ${{ steps.vars.outputs.short_sha }}
      is_build_triggered_by_workflow_dispatch: ${{ env.IS_BUILD_TRIGGERED_BY_WORKFLOW_DISPATCH }}
      service: ${{ env.SERVICE }}
      environment: ${{ env.ENVIRONMENT }}

 

  • 이렇게 쉽게 Github Action과 GCP Workload Federation을 사용해서, Image Build 후 Push 과정을 구성할 수 있다.

 

 


Reference

https://cloud.google.com/blog/products/devops-sre/using-github-actions-with-google-cloud-deploy?hl=en

https://gist.github.com/palewire/12c4b2b974ef735d22da7493cf7f4d37

https://cloud.google.com/iam/docs/workload-identity-federation?hl=ko&_gl=1*19geff0*_ga*MTk0NzM5NzU1My4xNjkwNDM2ODEz*_ga_WH2QY8WWF5*MTcxNjg3MjUwNi43NDkuMS4xNzE2ODc1MTYxLjAuMC4w&_ga=2.224028763.-1947397553.1690436813#impersonation

728x90
반응형