소개

이전 실습에서는 로봇 도우미가 창고에 자동으로 로그인했습니다. 그런데 비밀번호는 어디에서 가져왔을까요?

실제 자동화에서는 워크플로가 API 키, 비밀번호, 토큰과 같은 민감한 데이터를 사용해야 하는 경우가 많습니다. 이러한 값을 저장소 파일에 하드코딩해서는 안 됩니다.

GitHub 는 워크플로에서 사용하는 민감한 값을 보호된 방식으로 저장할 수 있도록 Secrets를 제공합니다. 파이프라인에는 권한이 부여된 액세스가 필요한 경우가 많으므로, 이는 CI/CD 보안의 핵심 관행입니다.

이는 자동화 보안에서 가장 중요한 경계 중 하나입니다. 파이프라인에는 자격 증명이 필요하지만, 자격 증명은 버전 관리에 커밋하지 않고 보호된 저장소에서 실행 시점에 주입해야 합니다.

이 실습에서는 다음을 수행합니다.

  • 보관소에 시크릿 비밀번호를 만듭니다.
  • 로봇이 비밀번호를 가져오도록 설정합니다.
  • 로봇이 비밀번호를 출력하려고 해도 GitHub 가 비밀번호를 검열한다는 것을 확인합니다.

사전 요구 사항

계속해서 github-actions-basics 저장소를 사용합니다.

시크릿 만들기

애플리케이션이 데이터베이스에 연결해야 한다고 가정해 보겠습니다. 데이터베이스 비밀번호를 안전하게 저장해야 합니다.

DB_PASSWORD라는 이름의 시크릿을 만듭니다.

  1. GitHub 에서 github-actions-basics 저장소를 엽니다.
  2. Settings 탭을 클릭합니다.
  3. 왼쪽 사이드바에서 Secrets and variables 메뉴 항목을 찾아 클릭해 펼칩니다.
  4. Actions를 선택합니다.
  5. New repository secret이라고 표시된 녹색 버튼을 클릭합니다.

New repository secret

간단한 입력 양식이 표시됩니다.

  • Name: DB_PASSWORD를 입력합니다. (시크릿 이름에는 대문자를 사용하는 것이 일반적입니다.)
  • Secret: SuperSafePassword123!을 입력합니다.

Add secret을 클릭합니다.

이제 DB_PASSWORD가 목록에 표시됩니다. 하지만 이제 값은 볼 수 없습니다. 시크릿을 저장하면 영구적으로 잠깁니다. 시크릿을 업데이트하거나 삭제할 수는 있지만, 저장한 값은 본인이나 다른 누구도 다시 확인할 수 없습니다.

시크릿 사용하기

이제 비밀번호를 안전한 보관소에 저장했으므로, 이 비밀번호를 사용하는 워크플로를 작성합니다.

여기서 중요한 패턴은 간접 참조입니다. 워크플로는 이름으로 시크릿을 참조하고, GitHub 는 실행 중에 값을 안전하게 확인합니다.

워크플로 파일에서는 ${{ secrets.YOUR_SECRET_NAME }} 구문을 사용해 모든 시크릿에 액세스할 수 있습니다.

프로젝트 디렉터리로 이동합니다.

cd ~/project
git clone https://github.com/your-username/github-actions-basics.git
cd github-actions-basics

참고: your-username을 실제 GitHub 사용자 이름으로 바꿉니다.

.github/workflows 폴더 안에 security-test.yml이라는 새 워크플로 파일을 만듭니다.

touch .github/workflows/security-test.yml

nano로 파일을 엽니다.

nano .github/workflows/security-test.yml

다음 내용을 추가합니다.

name: Security Test

on: [push]

jobs:
  test-secret:
    runs-on: ubuntu-latest
    steps:
      - name: Try to print secret
        env:
          MY_PASSWORD: ${{ secrets.DB_PASSWORD }}
        run: echo "The password is $MY_PASSWORD"

여기서는 흥미로운 작업을 수행합니다. GitHub 보관소의 시크릿을 MY_PASSWORD라는 환경 변수로 옮긴 다음, echo를 사용해 출력하려고 합니다.

잠깐! 비밀번호를 로그에 출력하는 것은 매우 위험하지 않나요? 맞습니다. 매우 위험합니다! 하지만 여기서는 GitHub Actions 의 강력한 보안 기능을 보여 주기 위해 이렇게 합니다.

nano에서 저장하고 종료합니다.

마스킹 확인하기

이제 이 워크플로를 실행하고 시크릿을 유출하려고 하면 어떻게 되는지 확인합니다.

변경 사항을 커밋하고 푸시합니다.

git add .
git commit -m "Test secret masking"
git push

GitHub 에서 저장소의 Actions로 이동합니다.

  1. "Security Test" 워크플로 실행을 클릭합니다.
  2. test-secret 작업을 클릭합니다.
  3. "Try to print secret" 단계를 펼칩니다.

출력을 확인합니다. 다음과 비슷한 내용이 표시되어야 합니다.

The password is ***

Secret masked

GitHub Actions 는 $MY_PASSWORD의 값이 시크릿에서 가져온 값임을 자동으로 인식합니다. 로그에 출력하기 전에 민감한 값을 검색하고 ***로 바꿉니다.

마스킹은 로그에 실수로 민감한 정보가 노출되는 피해를 줄여 주지만, 애초에 시크릿을 출력하지 않는 것이 더 나은 방법입니다. 보안 기능은 안전망이지, 부주의한 처리를 정당화하는 수단이 아닙니다.

이 "Masking" 기능이 사용자를 보호합니다. 실수로 시크릿을 출력하려고 하거나 사용 중인 도구가 지나치게 많은 정보를 출력하더라도, GitHub 가 이를 감지해 로그에서 민감한 데이터를 제거합니다.

GITHUB_TOKEN 참고: 이전 실습에서 사용한 ${{ secrets.GITHUB_TOKEN }}을 기억하시나요? 이 토큰도 정확히 같은 방식으로 작동합니다. GitHub 가 모든 실행마다 자동으로 만드는 시크릿이며, 그 값 역시 로그에서 마스킹됩니다.

요약

이 실습에서는 자동화 보안의 기본 사항을 배웠습니다.

  • 보관소: GitHub Secrets 를 사용해 비밀번호와 같은 민감한 데이터를 저장했습니다.
  • 액세스: ${{ secrets.NAME }}을 사용해 로봇이 해당 데이터에 액세스할 수 있도록 설정했습니다.
  • 마스킹: 실수로 정보가 유출되는 것을 방지하기 위해 GitHub 가 로그의 시크릿을 자동으로 삭제 (***) 하는지 확인했습니다.

이제 안전한 자동화 파이프라인을 갖추었습니다. 마지막 실습에서는 DevOps 의 궁극적인 목표인 Continuous Deployment를 다룹니다. 로봇이 코드를 실제 운영 서버에 배포하도록 만드는 방법을 배웁니다!