🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

GitHub Actions 환경변수와 시크릿 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 11. 28. · 15 Views

GitHub Actions 환경변수와 시크릿 완벽 가이드

GitHub Actions에서 환경변수와 시크릿을 안전하게 관리하는 방법을 알아봅니다. 워크플로우 설정부터 보안 모범 사례까지 실무에서 바로 활용할 수 있는 내용을 담았습니다.


목차

  1. 환경변수_정의_방법
  2. GitHub_기본_환경변수
  3. Repository_Secrets_설정
  4. Environment_Secrets
  5. GITHUB_TOKEN_활용
  6. 시크릿_보안_모범_사례

1. 환경변수 정의 방법

김개발 씨는 처음으로 GitHub Actions 워크플로우를 작성하게 되었습니다. 로컬에서는 잘 돌아가던 스크립트가 CI 환경에서는 계속 실패합니다.

알고 보니 환경변수를 설정하지 않아서 생긴 문제였습니다.

환경변수는 워크플로우가 실행되는 동안 사용할 수 있는 동적인 값입니다. 마치 메모장에 중요한 설정값을 적어두고 필요할 때마다 꺼내 보는 것과 같습니다.

GitHub Actions에서는 워크플로우, 잡, 스텝 세 가지 레벨에서 환경변수를 정의할 수 있어 유연한 설정이 가능합니다.

다음 코드를 살펴봅시다.

name: 환경변수 예제
on: push

# 워크플로우 전체에서 사용할 환경변수
env:
  NODE_VERSION: '18'
  APP_ENV: production

jobs:
  build:
    runs-on: ubuntu-latest
    # 이 잡에서만 사용할 환경변수
    env:
      BUILD_MODE: release
    steps:
      - name: 환경변수 출력
        # 이 스텝에서만 사용할 환경변수
        env:
          STEP_VAR: hello
        run: |
          echo "Node: $NODE_VERSION"
          echo "Build: $BUILD_MODE"
          echo "Step: $STEP_VAR"

김개발 씨는 입사한 지 두 달이 된 주니어 개발자입니다. 회사에서 처음으로 CI/CD 파이프라인을 구축하라는 미션을 받았습니다.

로컬 컴퓨터에서는 모든 테스트가 통과하는데, GitHub Actions에서 실행하면 자꾸 에러가 납니다. 선배 개발자 박시니어 씨가 슬쩍 모니터를 들여다봅니다.

"환경변수 설정은 했어요?" 김개발 씨는 멍한 표정을 지었습니다. "환경변수요?" 그렇다면 환경변수란 정확히 무엇일까요?

쉽게 비유하자면, 환경변수는 마치 호텔 체크인 시 받는 안내문과 같습니다. "와이파이 비밀번호는 1234입니다.

조식은 7시부터입니다." 이런 정보들이 적힌 안내문을 방에 두면, 투숙 기간 동안 언제든 참고할 수 있습니다. 환경변수도 마찬가지로 프로그램이 실행되는 동안 필요한 설정값을 담아두는 공간입니다.

환경변수가 없다면 어떤 일이 벌어질까요? 개발자들은 코드 안에 직접 설정값을 하드코딩해야 합니다.

"Node 버전은 18이고, 빌드 모드는 release야"라고 코드에 직접 써넣는 것입니다. 문제는 환경이 바뀔 때마다 코드를 수정해야 한다는 점입니다.

개발 환경에서는 debug 모드로, 운영 환경에서는 release 모드로 바꾸려면 매번 코드를 고쳐야 합니다. 바로 이런 불편함을 해결하기 위해 환경변수가 등장했습니다.

GitHub Actions에서는 세 가지 레벨에서 환경변수를 정의할 수 있습니다. 첫 번째는 워크플로우 레벨입니다.

파일 최상단에 env를 정의하면 모든 잡과 스텝에서 사용할 수 있습니다. 두 번째는 잡 레벨입니다.

특정 잡 안에서만 사용할 변수를 정의합니다. 세 번째는 스텝 레벨입니다.

하나의 스텝에서만 사용할 변수를 정의합니다. 위의 코드를 살펴보겠습니다.

맨 위에 정의된 NODE_VERSIONAPP_ENV는 워크플로우 전체에서 사용할 수 있습니다. 그 아래 build 잡 안에 정의된 BUILD_MODE는 이 잡 내에서만 유효합니다.

마지막으로 스텝 안에 정의된 STEP_VAR는 해당 스텝에서만 사용됩니다. 재미있는 점은 변수의 우선순위입니다.

만약 워크플로우 레벨에서 APP_ENV: production을 정의하고, 잡 레벨에서 APP_ENV: development를 정의하면 어떻게 될까요? 잡 레벨의 값이 우선합니다.

마치 전체 공지사항보다 개인에게 온 메시지가 더 중요한 것처럼, 더 구체적인 범위의 설정이 우선시됩니다. 실무에서는 이 특성을 활용해 기본값을 워크플로우 레벨에 두고, 필요한 곳에서만 덮어쓰는 패턴을 많이 사용합니다.

주의할 점도 있습니다. 환경변수에 민감한 정보를 직접 넣으면 안 됩니다.

API 키나 비밀번호 같은 정보는 누구나 볼 수 있는 워크플로우 파일에 노출됩니다. 이런 정보는 뒤에서 배울 시크릿을 사용해야 합니다.

다시 김개발 씨의 이야기로 돌아가 봅시다. 박시니어 씨의 설명을 들은 김개발 씨는 워크플로우 파일에 필요한 환경변수를 추가했습니다.

드디어 CI가 통과했습니다!

실전 팁

💡 - 환경변수 이름은 대문자와 언더스코어를 사용하는 것이 관례입니다

  • 변수 값에 공백이 있으면 따옴표로 감싸주세요

2. GitHub 기본 환경변수

김개발 씨가 워크플로우를 작성하다 보니 현재 브랜치 이름이나 커밋 SHA 값이 필요해졌습니다. 직접 정의해야 하나 고민하던 중, 박시니어 씨가 "GitHub이 기본으로 제공하는 환경변수가 있어요"라고 알려주었습니다.

GitHub 기본 환경변수는 모든 워크플로우에서 자동으로 사용할 수 있는 변수들입니다. 마치 호텔에 체크인하면 기본 어메니티가 준비되어 있는 것처럼, GitHub Actions도 자주 사용하는 정보들을 미리 준비해둡니다.

현재 브랜치, 커밋 정보, 저장소 이름 등 유용한 정보를 바로 사용할 수 있습니다.

다음 코드를 살펴봅시다.

name: 기본 환경변수 활용
on: push

jobs:
  info:
    runs-on: ubuntu-latest
    steps:
      - name: GitHub 기본 환경변수 출력
        run: |
          echo "저장소: $GITHUB_REPOSITORY"
          echo "브랜치: $GITHUB_REF_NAME"
          echo "커밋 SHA: $GITHUB_SHA"
          echo "워크플로우: $GITHUB_WORKFLOW"
          echo "실행 번호: $GITHUB_RUN_NUMBER"
          echo "액터: $GITHUB_ACTOR"
          echo "이벤트: $GITHUB_EVENT_NAME"
          echo "작업 디렉토리: $GITHUB_WORKSPACE"

김개발 씨는 배포 자동화 스크립트를 작성하고 있었습니다. 배포할 때 어떤 브랜치에서 배포되었는지, 누가 커밋을 올렸는지 기록을 남기고 싶었습니다.

"이 정보들을 어떻게 가져오지?" 고민하던 찰나, 박시니어 씨가 다가왔습니다. "GitHub Actions는 기본으로 제공하는 환경변수가 꽤 많아요.

직접 정의할 필요 없이 바로 쓰면 돼요." 기본 환경변수란 무엇일까요? 이것은 마치 스마트폰을 사면 기본 앱이 설치되어 있는 것과 같습니다.

전화, 문자, 카메라처럼 자주 사용하는 앱은 따로 설치하지 않아도 바로 쓸 수 있습니다. GitHub Actions도 마찬가지로 개발자들이 자주 필요로 하는 정보를 미리 환경변수로 만들어 놓았습니다.

가장 자주 사용하는 기본 환경변수들을 살펴보겠습니다. GITHUB_REPOSITORY는 현재 저장소의 소유자와 이름을 알려줍니다.

예를 들어 octocat/Hello-World 형식입니다. 여러 저장소에서 공용으로 사용하는 워크플로우를 만들 때 유용합니다.

GITHUB_REF_NAME은 현재 브랜치나 태그 이름을 담고 있습니다. main, feature/login, v1.0.0 같은 값이 들어갑니다.

브랜치별로 다른 동작을 하고 싶을 때 자주 사용합니다. GITHUB_SHA는 워크플로우를 트리거한 커밋의 전체 SHA 값입니다.

40자리의 긴 해시값으로, 정확한 커밋을 추적할 때 사용합니다. Docker 이미지 태그에 커밋 SHA를 넣는 것이 대표적인 활용 사례입니다.

GITHUB_ACTOR는 워크플로우를 실행시킨 사람의 GitHub 아이디입니다. 누가 배포를 트리거했는지 슬랙 알림에 포함시킬 때 유용합니다.

GITHUB_RUN_NUMBER는 저장소 내에서 해당 워크플로우가 몇 번째로 실행되었는지 알려줍니다. 빌드 번호로 활용하기 좋습니다.

참고로 GITHUB_RUN_ID는 GitHub 전체에서 유일한 실행 ID입니다. GITHUB_WORKSPACE는 저장소가 체크아웃되는 기본 작업 디렉토리입니다.

파일 경로를 다룰 때 이 변수를 기준으로 상대 경로를 지정하면 편리합니다. 실무에서는 이 변수들을 조합해서 다양한 자동화를 구현합니다.

예를 들어 Docker 이미지를 빌드할 때 $GITHUB_REPOSITORY:$GITHUB_SHA 형식으로 태그를 만들면, 어떤 저장소의 어떤 커밋에서 만들어진 이미지인지 바로 알 수 있습니다. 슬랙 알림을 보낼 때 $GITHUB_ACTOR님이 $GITHUB_REF_NAME 브랜치에서 배포했습니다라고 메시지를 구성할 수도 있습니다.

주의할 점이 있습니다. 기본 환경변수 중 일부는 이벤트 종류에 따라 다른 값을 가집니다.

예를 들어 GITHUB_REF는 push 이벤트에서는 브랜치 ref이지만, pull request 이벤트에서는 PR의 병합 브랜치 ref입니다. 공식 문서를 참고해서 각 상황에 맞는 변수를 선택해야 합니다.

김개발 씨는 기본 환경변수들을 활용해 배포 로그를 깔끔하게 정리했습니다. "이제 누가 언제 어떤 커밋을 배포했는지 한눈에 볼 수 있겠네요!"

실전 팁

💡 - GitHub 컨텍스트 ${{ github.* }}를 사용하면 더 많은 정보에 접근할 수 있습니다

  • 기본 환경변수는 이름이 GITHUB_로 시작하므로, 사용자 정의 변수와 충돌을 피하세요

3. Repository Secrets 설정

김개발 씨가 AWS에 배포하는 워크플로우를 작성하려고 합니다. AWS 액세스 키가 필요한데, 이걸 워크플로우 파일에 그대로 적어도 될까요?

박시니어 씨가 단호하게 말합니다. "절대 안 돼요!

시크릿을 사용해야 해요."

Repository Secrets는 민감한 정보를 안전하게 저장하고 워크플로우에서 사용할 수 있게 해주는 기능입니다. 마치 은행 금고에 귀중품을 맡기는 것처럼, 비밀번호나 API 키 같은 중요한 정보를 GitHub이 암호화하여 보관합니다.

저장소 설정에서 등록하면 워크플로우에서 안전하게 참조할 수 있습니다.

다음 코드를 살펴봅시다.

name: 시크릿을 사용한 배포
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: AWS 자격 증명 설정
        uses: aws-actions/configure-aws-credentials@v4
        with:
          # 시크릿은 ${{ secrets.이름 }} 형식으로 참조
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-2

      - name: S3에 배포
        run: aws s3 sync ./dist s3://${{ secrets.S3_BUCKET_NAME }}

김개발 씨는 신나게 AWS 배포 워크플로우를 작성하고 있었습니다. 그러다 문득 손이 멈췄습니다.

"AWS 액세스 키를 여기에 그냥 적어도 되나?" 옆에서 지켜보던 박시니어 씨가 소스라치게 놀랐습니다. "잠깐, 그거 커밋하면 큰일 나요!

시크릿을 사용해야 해요." Repository Secrets란 무엇일까요? 이것은 마치 은행 금고와 같습니다.

집에 현금을 두면 도둑이 가져갈 수 있지만, 은행 금고에 맡기면 안전합니다. 필요할 때는 신분증을 보여주고 꺼내 쓸 수 있습니다.

GitHub Secrets도 마찬가지입니다. 민감한 정보를 GitHub의 암호화된 저장소에 보관하고, 워크플로우가 실행될 때만 안전하게 전달받습니다.

시크릿을 설정하는 방법은 간단합니다. 저장소 페이지에서 Settings 탭으로 이동합니다.

왼쪽 메뉴에서 Secrets and variables > Actions를 선택합니다. New repository secret 버튼을 클릭하고 이름과 값을 입력합니다.

이름은 대문자와 언더스코어로 작성하는 것이 관례입니다. 워크플로우에서는 ${{ secrets.시크릿이름 }} 형식으로 참조합니다.

위 코드에서 ${{ secrets.AWS_ACCESS_KEY_ID }}는 저장소 시크릿에 등록된 AWS 액세스 키 값으로 대체됩니다. 중요한 점은 이 값이 워크플로우 파일에는 전혀 노출되지 않는다는 것입니다.

누군가 워크플로우 파일을 봐도 실제 키 값은 알 수 없습니다. 시크릿의 또 다른 보안 기능은 로그 마스킹입니다.

실수로 시크릿 값을 echo로 출력하려 해도 로그에는 ***로 표시됩니다. GitHub이 자동으로 시크릿 값을 감지하고 마스킹 처리하기 때문입니다.

다만 이것이 완벽한 보안을 보장하지는 않습니다. 예를 들어 시크릿 값을 base64로 인코딩해서 출력하면 마스킹이 되지 않을 수 있습니다.

시크릿을 사용할 때 알아야 할 규칙이 있습니다. 시크릿 이름에는 알파벳, 숫자, 언더스코어만 사용할 수 있습니다.

GITHUB_로 시작하는 이름은 예약되어 있어 사용할 수 없습니다. 시크릿 값의 최대 크기는 64KB입니다.

저장소당 최대 100개의 시크릿을 등록할 수 있습니다. 실무에서 자주 등록하는 시크릿 종류를 살펴보겠습니다.

클라우드 서비스 자격 증명은 필수입니다. AWS 키, GCP 서비스 계정, Azure 인증 정보 등이 여기에 해당합니다.

npm이나 PyPI 같은 패키지 레지스트리의 토큰도 자주 사용합니다. 슬랙 웹훅 URL, 데이터베이스 접속 정보, 외부 API 키 등도 시크릿으로 관리합니다.

주의할 점이 있습니다. 포크된 저장소에서 실행되는 워크플로우는 원본 저장소의 시크릿에 접근할 수 없습니다.

이는 보안을 위한 의도된 설계입니다. 악의적인 PR이 시크릿을 탈취하는 것을 방지합니다.

김개발 씨는 AWS 자격 증명을 시크릿으로 등록하고 워크플로우를 수정했습니다. "이제 안전하게 배포할 수 있겠네요!"

실전 팁

💡 - 시크릿 값은 한 번 저장하면 다시 볼 수 없으니 별도로 안전하게 보관하세요

  • 팀원 변경 시 관련 시크릿을 로테이션하는 것이 좋습니다

4. Environment Secrets

김개발 씨의 회사에는 개발, 스테이징, 운영 세 가지 환경이 있습니다. 각 환경마다 다른 데이터베이스를 사용하는데, 이 접속 정보를 어떻게 관리해야 할까요?

박시니어 씨가 답합니다. "Environment를 사용하면 환경별로 시크릿을 분리할 수 있어요."

Environment Secrets는 배포 환경별로 시크릿을 분리하여 관리하는 기능입니다. 마치 사무실, 창고, 공장에 각각 다른 열쇠를 사용하는 것처럼, 개발/스테이징/운영 환경마다 다른 설정값을 가질 수 있습니다.

또한 보호 규칙을 설정하여 운영 환경 배포 전 승인을 받도록 할 수도 있습니다.

다음 코드를 살펴봅시다.

name: 환경별 배포
on:
  push:
    branches: [main, develop]

jobs:
  deploy-staging:
    if: github.ref == 'refs/heads/develop'
    runs-on: ubuntu-latest
    # staging 환경의 시크릿 사용
    environment: staging
    steps:
      - uses: actions/checkout@v4
      - name: 스테이징 배포
        run: |
          echo "스테이징 서버에 배포합니다"
          # staging 환경에 등록된 시크릿 사용
          ./deploy.sh ${{ secrets.API_URL }} ${{ secrets.DB_HOST }}

  deploy-production:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    # production 환경의 시크릿 사용 (승인 필요)
    environment: production
    steps:
      - uses: actions/checkout@v4
      - name: 운영 배포
        run: |
          echo "운영 서버에 배포합니다"
          ./deploy.sh ${{ secrets.API_URL }} ${{ secrets.DB_HOST }}

김개발 씨는 새로운 고민에 빠졌습니다. 스테이징 서버와 운영 서버의 데이터베이스 주소가 다릅니다.

그런데 시크릿 이름을 STAGING_DB_HOST, PRODUCTION_DB_HOST처럼 따로 만들자니 워크플로우가 복잡해집니다. 박시니어 씨가 해결책을 제시합니다.

"GitHub의 Environment 기능을 사용해봐요. 환경별로 같은 이름의 시크릿을 다른 값으로 설정할 수 있어요." Environment란 무엇일까요?

이것은 마치 같은 회사의 여러 지점과 같습니다. 서울 지점, 부산 지점, 제주 지점이 있다고 해봅시다.

각 지점은 같은 시스템을 사용하지만, 접속하는 서버는 다릅니다. 직원들은 자신이 속한 지점의 서버에만 접속합니다.

Environment도 마찬가지로 같은 워크플로우가 환경에 따라 다른 설정을 사용하게 해줍니다. Environment를 설정하는 방법을 알아보겠습니다.

저장소의 Settings에서 Environments를 선택합니다. New environment를 클릭하고 이름을 입력합니다.

보통 development, staging, production 같은 이름을 사용합니다. 생성된 환경에 들어가면 시크릿과 변수를 등록할 수 있습니다.

위 코드를 보면 environment: stagingenvironment: production이 눈에 띕니다. 이 한 줄이 핵심입니다.

같은 secrets.DB_HOST를 참조해도 staging 환경에서는 스테이징 DB 주소가, production 환경에서는 운영 DB 주소가 주입됩니다. 코드는 같지만 결과가 다른 것입니다.

Environment의 진정한 힘은 보호 규칙에 있습니다. 운영 환경에는 실수로 배포하면 큰 문제가 생길 수 있습니다.

Environment 설정에서 Required reviewers를 지정하면, 해당 환경으로 배포하기 전에 지정된 사람의 승인을 받아야 합니다. 워크플로우가 environment: production에 도달하면 멈추고 승인을 기다립니다.

추가적인 보호 규칙도 설정할 수 있습니다. Wait timer를 설정하면 배포 전 일정 시간 대기합니다.

예를 들어 30분을 설정하면 실수를 발견했을 때 취소할 시간을 벌 수 있습니다. Deployment branches를 설정하면 특정 브랜치에서만 해당 환경으로 배포할 수 있습니다.

운영 환경은 main 브랜치에서만 배포 가능하게 제한하는 것이 일반적입니다. 실무에서는 이런 패턴을 많이 사용합니다.

develop 브랜치에 push하면 자동으로 스테이징 환경에 배포됩니다. main 브랜치에 push하면 운영 환경 배포가 트리거되지만, 팀장의 승인을 기다립니다.

팀장이 GitHub에서 Approve 버튼을 누르면 그제야 운영 배포가 진행됩니다. 주의할 점이 있습니다.

Environment 시크릿과 Repository 시크릿에 같은 이름이 있으면 Environment 시크릿이 우선합니다. 이 특성을 활용해서 Repository 시크릿에 기본값을 두고, 특정 환경에서만 다른 값을 사용하게 할 수도 있습니다.

김개발 씨는 Environment를 설정하고 나서 마음이 놓였습니다. "이제 실수로 운영 서버에 잘못 배포할 걱정이 없겠네요!"

실전 팁

💡 - 운영 환경에는 반드시 승인 절차를 추가하세요

  • Environment URL을 설정하면 배포 기록에서 바로 해당 환경으로 이동할 수 있습니다

5. GITHUB TOKEN 활용

김개발 씨가 PR이 생성되면 자동으로 댓글을 다는 워크플로우를 만들고 있습니다. GitHub API를 호출하려면 인증 토큰이 필요한데, 별도로 토큰을 발급받아야 할까요?

박시니어 씨가 말합니다. "GITHUB_TOKEN을 사용하면 돼요.

자동으로 제공되거든요."

GITHUB_TOKEN은 워크플로우가 실행될 때 GitHub이 자동으로 생성하는 인증 토큰입니다. 마치 회사 출입 카드가 자동으로 발급되는 것처럼, 별도의 설정 없이 저장소 내에서 다양한 GitHub 작업을 수행할 수 있습니다.

권한은 워크플로우 파일에서 세밀하게 조정할 수 있습니다.

다음 코드를 살펴봅시다.

name: PR 자동 라벨링
on:
  pull_request:
    types: [opened]

# 워크플로우 레벨에서 권한 설정
permissions:
  pull-requests: write
  contents: read

jobs:
  label:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: PR에 라벨 추가
        # GITHUB_TOKEN을 사용한 GitHub CLI 명령
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          # 변경된 파일 경로에 따라 라벨 추가
          if gh pr diff ${{ github.event.number }} | grep -q "^+.*\.ts"; then
            gh pr edit ${{ github.event.number }} --add-label "typescript"
          fi

      - name: PR에 환영 댓글 작성
        uses: actions/github-script@v7
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: 'PR을 올려주셔서 감사합니다!'
            })

김개발 씨는 팀의 코드 리뷰 프로세스를 개선하고 싶었습니다. PR이 올라오면 자동으로 변경된 파일 유형에 따라 라벨을 붙이고, 환영 메시지를 남기면 좋겠다고 생각했습니다.

그런데 GitHub API를 호출하려면 인증이 필요합니다. "Personal Access Token을 발급받아서 시크릿에 등록해야 하나?" 고민하던 김개발 씨에게 박시니어 씨가 다가왔습니다.

"GITHUB_TOKEN이라는 게 있어요. 자동으로 제공되니까 따로 발급받을 필요 없어요." GITHUB_TOKEN이란 무엇일까요?

이것은 마치 회사 임시 출입증과 같습니다. 외부 협력업체 직원이 방문하면 안내 데스크에서 임시 출입증을 발급합니다.

이 출입증으로 필요한 구역에만 출입할 수 있고, 업무가 끝나면 자동으로 회수됩니다. GITHUB_TOKEN도 워크플로우가 시작될 때 자동 생성되고, 종료되면 만료됩니다.

GITHUB_TOKEN의 기본 권한은 무엇일까요? 저장소의 코드 읽기, 패키지 게시, PR과 이슈 관리 등 대부분의 작업이 가능합니다.

하지만 보안을 위해 워크플로우 파일 수정이나 새 워크플로우 트리거는 기본적으로 제한됩니다. 포크된 저장소에서 실행되는 워크플로우의 권한은 더 제한적입니다.

권한을 명시적으로 설정하는 것이 좋습니다. 위 코드에서 permissions 블록을 주목해주세요.

pull-requests: write는 PR에 라벨을 추가하거나 댓글을 쓸 수 있게 합니다. contents: read는 코드를 읽을 수만 있습니다.

이렇게 필요한 권한만 명시하면 토큰이 탈취되어도 피해를 최소화할 수 있습니다. 워크플로우에서 GITHUB_TOKEN을 사용하는 방법은 두 가지입니다.

첫 번째는 ${{ secrets.GITHUB_TOKEN }}으로 참조하는 방법입니다. 시크릿처럼 사용하지만 실제로는 자동 생성된 토큰입니다.

두 번째는 ${{ github.token }}으로 참조하는 방법입니다. 둘 다 같은 토큰을 가리킵니다.

실무에서 GITHUB_TOKEN이 유용한 상황을 살펴보겠습니다. PR에 자동으로 라벨을 붙이거나 리뷰어를 할당할 때 사용합니다.

이슈를 생성하거나 댓글을 달 때 사용합니다. 릴리스를 생성하고 에셋을 업로드할 때 사용합니다.

GitHub Container Registry에 Docker 이미지를 푸시할 때도 사용합니다. GITHUB_TOKEN으로는 할 수 없는 것도 있습니다.

다른 워크플로우를 트리거하는 것은 불가능합니다. 워크플로우 A가 GITHUB_TOKEN으로 커밋을 푸시해도 워크플로우 B가 실행되지 않습니다.

무한 루프를 방지하기 위한 설계입니다. 이런 경우에는 Personal Access Token이나 GitHub App 토큰을 사용해야 합니다.

주의할 점이 있습니다. permissions를 한 번이라도 명시하면 명시하지 않은 권한은 모두 none이 됩니다.

예를 들어 contents: write만 적으면 PR 관련 권한이 없어집니다. 필요한 권한을 빠짐없이 나열해야 합니다.

김개발 씨는 GITHUB_TOKEN을 활용해 PR 자동화를 완성했습니다. "Personal Access Token을 발급받고 시크릿에 등록하는 번거로움 없이 바로 사용할 수 있어서 편하네요!"

실전 팁

💡 - 최소 권한 원칙을 따라 필요한 권한만 명시하세요

  • 다른 워크플로우를 트리거해야 한다면 Personal Access Token이나 GitHub App을 사용하세요

6. 시크릿 보안 모범 사례

김개발 씨가 작성한 워크플로우가 잘 동작합니다. 그런데 박시니어 씨가 심각한 표정으로 다가옵니다.

"코드는 잘 작성했는데, 보안 측면에서 몇 가지 개선이 필요해요. 시크릿은 한 번 유출되면 큰 문제가 생길 수 있거든요."

시크릿 보안 모범 사례는 민감한 정보가 유출되지 않도록 지켜야 할 규칙들입니다. 마치 금고 열쇠를 안전하게 관리하는 것처럼, 시크릿도 생성부터 사용, 폐기까지 전 과정에서 주의가 필요합니다.

최소 권한 원칙과 정기적인 로테이션이 핵심입니다.

다음 코드를 살펴봅시다.

name: 보안 모범 사례 적용
on:
  push:
    branches: [main]

# 최소 권한 원칙 적용
permissions:
  contents: read

jobs:
  secure-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # 시크릿은 환경변수로 전달 (인자로 직접 전달 지양)
      - name: 안전한 시크릿 사용
        env:
          API_KEY: ${{ secrets.API_KEY }}
          DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
        run: |
          # 시크릿 값을 직접 출력하지 않음
          # echo $API_KEY  <-- 이렇게 하면 안 됨

          # 환경변수로 프로그램에 전달
          node deploy.js

      # 파일로 시크릿을 저장해야 할 경우 임시 파일 사용
      - name: 인증서 파일 생성
        env:
          CERT_CONTENT: ${{ secrets.SSL_CERTIFICATE }}
        run: |
          echo "$CERT_CONTENT" > /tmp/cert.pem
          chmod 600 /tmp/cert.pem
          # 사용 후 즉시 삭제
          ./use-cert.sh /tmp/cert.pem
          rm -f /tmp/cert.pem

김개발 씨는 CI/CD 파이프라인을 성공적으로 구축했다고 생각했습니다. 그런데 박시니어 씨가 보안 점검을 하더니 몇 가지 문제를 발견했습니다.

"시크릿 관리가 조금 허술해요. 지금은 괜찮아 보여도, 나중에 큰 문제가 될 수 있어요." 시크릿 보안이 왜 중요할까요?

이것은 마치 집 열쇠 관리와 같습니다. 열쇠를 아무 데나 두면 도둑이 들 수 있습니다.

열쇠를 분실하면 자물쇠를 교체해야 합니다. 열쇠를 여러 개 만들면 관리가 어려워집니다.

시크릿도 마찬가지입니다. 한 번 유출되면 AWS 비용 폭탄, 데이터 유출, 서비스 마비 등 심각한 결과를 초래할 수 있습니다.

첫 번째 원칙은 최소 권한입니다. 시크릿이 가진 권한은 꼭 필요한 것만 포함해야 합니다.

AWS 키를 예로 들면, 전체 관리자 권한 대신 S3 특정 버킷에만 접근할 수 있는 권한을 부여하세요. 시크릿이 유출되어도 피해 범위를 최소화할 수 있습니다.

두 번째 원칙은 로그 노출 방지입니다. GitHub이 자동으로 시크릿을 마스킹하지만, 완벽하지 않습니다.

시크릿 값을 base64로 인코딩하거나 한 글자씩 출력하면 마스킹을 우회할 수 있습니다. 따라서 디버깅 목적으로도 시크릿을 출력하지 마세요.

꼭 확인이 필요하면 로컬 환경에서 테스트하세요. 세 번째 원칙은 환경변수로 전달입니다.

시크릿을 명령줄 인자로 직접 전달하면 프로세스 목록에 노출될 수 있습니다. ./script.sh ${{ secrets.API_KEY }} 대신 환경변수로 설정하고 스크립트 내에서 읽도록 하세요.

위 코드의 env 블록처럼 말입니다. 네 번째 원칙은 정기적인 로테이션입니다.

아무리 잘 관리해도 시크릿은 정기적으로 교체해야 합니다. 3개월에서 6개월 주기로 새 키를 발급받고 이전 키를 폐기하세요.

팀원이 퇴사했을 때도 관련 시크릿을 즉시 로테이션해야 합니다. 다섯 번째 원칙은 접근 권한 감사입니다.

저장소 시크릿에 접근할 수 있는 사람이 누구인지 파악하세요. Organization 설정에서 시크릿 접근 로그를 확인할 수 있습니다.

불필요한 접근 권한은 제거하고, 정기적으로 감사를 수행하세요. 여섯 번째는 포크 저장소 주의입니다.

외부 기여자가 올린 PR은 포크된 저장소에서 실행됩니다. 이때 원본 저장소의 시크릿에 접근할 수 없도록 설계되어 있습니다.

하지만 pull_request_target 이벤트를 사용하면 시크릿에 접근할 수 있어 악용될 수 있습니다. 외부 PR에서 시크릿이 필요한 작업은 maintainer의 승인 후에만 실행되도록 설정하세요.

추가적인 팁을 드리겠습니다. 시크릿을 파일로 저장해야 할 경우 임시 디렉토리를 사용하고, 사용 후 즉시 삭제하세요.

위 코드에서 인증서를 /tmp에 저장하고 rm -f로 삭제하는 것처럼 말입니다. git history에 시크릿이 남지 않도록 주의하세요.

.env 파일은 반드시 .gitignore에 추가해야 합니다. 김개발 씨는 박시니어 씨의 조언을 듣고 워크플로우를 수정했습니다.

"보안은 한 번 설정하고 끝이 아니라 계속 신경 써야 하는군요!" 박시니어 씨가 고개를 끄덕입니다. "맞아요.

보안 사고는 발생한 후에 수습하기보다 미리 예방하는 게 훨씬 쉬워요."

실전 팁

💡 - 시크릿 유출이 의심되면 즉시 로테이션하고 영향 범위를 파악하세요

  • GitHub의 secret scanning 기능을 활성화하여 실수로 커밋된 시크릿을 감지하세요

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#GitHub Actions#환경변수#Secrets#CI/CD#DevOps#GitHub Actions,CI/CD,DevOps

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.