GitHub Actions를 이용해 AWS CDK를 배포해보자!

GitHub Actions를 이용해 AWS CDK를 배포하는 방법을 실습과 함께 설명드립니다. 직접 따라해보면서 감각을 익힙시다.
2022.12.13

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

안녕하세요, 클래스메서드 CX사업본부 Delivery부의 정현재입니다.

이번 블로그에서는 GitHub Actions를 이용하여 AWS CDK를 배포 하는 방법에 대해 간단한 실습과 함께 정리하려고 합니다. 매우 간단하니 직접 해보시면서 감각을 익히실 수 있으시면 좋겠습니다. 그러면 시작하도록 하겠습니다.

GitHub Actions 란

우선, GitHub Actions에 대해서 간단히 정리하도록 하겠습니다. GitHub Actions는 GitHub에서 제공하는 코드의 빌드, 테스트, 배포 등과 같은 워크플로우를 자동화할 수 있도록 하는 CI/CD 툴입니다. 원하는 작업을 워크플로우로 한번 작성해두면 자동적으로 GitHub Actions에서 실행을 할 수 있기 때문에 수동으로 했을 때보다 실수를 줄일 수 있고, 시간도 절약할 수 있습니다. 비용은 Public 저장소의 경우는 무료, Private 저장소의 경우는 실행 시간 단위로 요금을 발생하게 됩니다. 그러면 워크플로우를 어떻게 작성하면 되는지에 대한 자세한 내용은 실습을 하면서 설명드리도록 하겠습니다.

GitHub Actions로 AWS CDK를 배포 해보자

AWS CDK 프로젝트 작성 및 람다 함수 작성

이번 실습에서는 간단히 Lambda 함수 하나를 작성하여 배포해보도록 하겠습니다.

우선 새로운 폴더를 만들고 cdk init 명령어를 이용해 새로운 AWS CDK 프로젝트를 작성합니다. 언어는 typescript를 지정하고 있지만 원하는 언어를 사용하셔도 무방합니다.

mkdir cdk-ga-test && cd cdk-ga-test
cdk init app --language typescript

아래와 같은 프로젝트가 생성 되었을 것입니다.

├── README.md
├── bin
│   └── cdk-ga-test.ts
├── cdk.json
├── jest.config.js
├── lib
│   └── cdk-ga-test-stack.ts
├── package-lock.json
├── package.json
├── test
│   └── cdk-ga-test.test.ts
└── tsconfig.json

handler 폴더를 만들고 그 안에 function.ts라는 파일을 만들어 핸들러를 작성합니다.

handler/function.ts

export const handler = async (event: any) => {
  console.log(JSON.stringify(event))
      
  return {
      statuscode: 200,
      body: 'Hello CDK'
  }
}

핸들러를 만들었으니, CDK 스택을 아래와 같이 수정합니다.

lib/cdk-ga-test-stack.ts

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as lambda from 'aws-cdk-lib/aws-lambda';

export class CdkGaTestStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const demoFunction = new lambda.Function(this, 'demoFunction', {
      code: lambda.Code.fromAsset('handler'),
      handler: 'function.handler',
      runtime: lambda.Runtime.NODEJS_16_X
    })
  }
}

GitHub 리포지토리 생성

방금 작성한 코드를 올릴 GitHub 리포지토리를 하나 만듭니다. Private 리포지토리의 경우 GitHub Actions가 유료이므로, 이번 실습에서는 Public 리포지토리를 만들도록 하겠습니다.

AWS OIDC 작성

GitHub Actions는 Open ID Connect를 지원합니다. Open ID Connect를 사용하게 되면 배포할 때마다 매번 AWS의 자격증명을 제공할 필요가 없고, 단일 리포지토리/워크플로우에서만 유효한 단기 액세스 토큰을 발행(발급 후 자동으로 만료)해주는 등 여러가지 이점이 있습니다.

그러면 OIDC의 자격 증명 공급자 작성을 해보도록 하겠습니다. AWS Management Console에서 IAM 화면으로 이동합니다. 자격 증명 공급자 탭을 클릭 후, 공급자 추가를 클릭합니다. 다음과 같이 입력하여 공급자를 작성합니다. 공급자 URL의 경우, 입력 후 지문 가져오기를 클릭하여 지문을 작성하여야 공급자 작성이 가능합니다.

  • 공급자 유형: OpenID Connect
  • 공급자 URL: https://token.actions.githubusercontent.com
  • 대상: sts.amazonaws.com

AWS IAM Role 작성

자격 증명 공급자 작성 후, GitHub Actions의 워크플로우에서 사용할 IAM Role을 작성합니다. 신뢰할 수 있는 엔터티 유형은 웹 자격 증명을 선택 후, 방금 만든 OIDC의 공급자를 지정합니다.

권한 추가에서는 새롭게 정책을 생성합니다. CDK에서 생성하는 리소스에 따라 필요한 권한만 주는 것이 이상적이지만, 이번 실습에서는 모든 리소스를 만들 수 있도록 * 를 지정하겠습니다.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "*",
      "Resource": "*"
    }
  ]
}

권한을 추가해준 후, IAM Role의 이름을 지정하고 역할을 생성합니다. 그 후, 생성한 IAM Role의 신뢰 관계를 편집합니다. 특정 GitHub Repository에서 작업할 때만 자격 증명 공급자를 신뢰하도록 Condition 부분을 수정합니다.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::***********:oidc-provider/token.actions.githubusercontent.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringLike": {
          "token.actions.githubusercontent.com:sub": "repo:<GitHub Account>/<GitHub Repository>:*"
        }
      }
    }
  ]
}

GitHub Actions Secrets 작성

이제 GitHub Actions 워크플로우에서 사용할 정보를 Secrets에 저장합니다.

저장할 정보는 이하의 두 가지입니다.

  • OIDC_ROLE_ARN: 작성한 IAM Role의 ARN
  • REGION: 배포할 AWS 리전

GitHub Actions 워크플로우 작성

마지막으로 GitHub Actions 워크플로우를 작성합니다.

워크플로우를 작성하기 전에, CDK 배포 스크립트를 package.json에 추가해줍니다.

package.json

{
  "name": "cdk-ga-test",
  "version": "0.1.0",
  "bin": {
    "cdk-ga-test": "bin/cdk-ga-test.js"
  },
  "scripts": {
    .
    .
    .
    "deploy": "cdk deploy --require-approval never"
  },
  .
  .
  .
}

.github/workflows 폴더를 작성 후, cdk-deploy.yml라는 yml 파일을 만듭니다. 그 후, 다음과 같이 코드를 작성합니다.

.github/workflows/cdk-deploy.yml

name: cdk deploy

on:
  push:
    branches:
      - main
jobs:
  aws_cdk:
    name: Running Ubutu image
    runs-on: ubuntu-18.04

    strategy:
      matrix:
        node-version: [16.x]

    permissions:
      id-token: write
      contents: read

    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Setup Node
        uses: actions/setup-node@v2
        with:
          node-version: '16'

      # AWS 자격증명 취득
      # https://github.com/aws-actions/configure-aws-credentials
      - name: Configure AWS credentials from IAM Role
        uses: aws-actions/configure-aws-credentials@v1
        with:
          role-to-assume: ${{ secrets.OIDC_ROLE_ARN }}
          aws-region: ${{ secrets.REGION }}

      - name: Install Dependencies
        run: npm ci

      - name: Build Code
        run: |
          npm run build

      # CDK 배포
      - name: CDK deploy Api Stack
        run: npm run deploy

필요에 따라 테스트 등의 step을 추가할 수 있습니다. 워크플로우에서 사용하는 구문에 대해서 자세히 알고 싶으신 분은 공식 문서를 참고해주세요

GitHub Actions 워크플로우 실행

만약 CDK를 처음 배포하는 경우라면, CDK 배포 시 필요한 S3 버킷을 아래의 커맨드로 생성할 필요가 있습니다.

cdk bootstrap

이번 실습에서 main 브랜치에 push 이벤트가 발생하면 워크플로우가 동작하도록 하였기 때문에, 아까 만든 리포지토리의 main 브랜치에 코드를 push 합니다.

git add .
git commit -m "GA Test"
git branch -M main
git remote add origin https://github.com/*******/cdk-ga-test.git
git push -u origin main

push를 하고, 해당 리포지토리에 이동하면 다음과 같이 GitHub Actions의 워크플로우가 실행 중인 것을 확인할 수 있습니다.

워크플로우의 작업들이 전부 정상적으로 완료 되었으면, CloudFormation 스택이 생성되어 있고, 람다 함수도 정상적으로 작성된 것을 확인할 수 있습니다.

마무리

이번 블로그에서는 GitHub Actions를 이용해 AWS CDK를 배포해보았습니다. 실습을 위해 굉장히 간단한 구성을 배포해보았습니다만, CDK에서 생성하는 리소스, GitHub Actions 워크플로우에서 실행할 작업 내용에 따라 적당히 수정하면서 사용하시길 바랍니다. 읽어주셔서 감사합니다.