CI/CD
GitHub Actions에서 secret 누락을 빨리 알아채기
배포 스크립트에서 환경 변수를 빼먹으면, 배포는 성공해도 서비스는 작동하지 않는다.
GitHub Actions로 배포할 때 가장 흔한 실수는 secret이 누락되는 것이다. workflow는 성공했는데, 배포된 애플리케이션이 작동하지 않는다. 원인은 대부분 환경 변수가 없기 때문이다.
문제: 조용한 실패
name: Deploy
on: [push]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy
run: |
docker build -t myapp:latest .
docker push myapp:latest
Workflow는 초록색으로 완료되지만, 배포된 앱을 열면 에러다. 왜? SECRET이나 환경 변수를 정의하지 않았기 때문이다.
CI/CD 시스템은 빌드와 배포만 확인한다. 앱이 실제로 작동하는지는 모른다.
원인 분석
Secret이 누락되는 경우:
1. 개발 중에는 .env 파일을 썼는데, CI에 secret으로 등록하지 않음
# 로컬 실행 (잘 작동)
POST_API_KEY=abc123 npm run build
# CI 실행 (secret 없음)
DOCKER_BUILD_ARGS="--build-arg POST_API_KEY=" docker build .
# → POST_API_KEY가 빈 문자열
2. Secret 이름을 잘못 입력
GitHub UI에서 POST_API_KEY로 저장했는데, workflow에서 API_KEY로 참조했다.
# 정의: POST_API_KEY
# 사용: API_KEY ← 틀림!
run: docker build --build-arg API_KEY=${{ secrets.API_KEY }}
3. 새 repository로 옮기면서 secrets를 복사하지 않음
모든 secrets을 다시 설정해야 한다.
조기 발견 방법
1단계: Workflow에서 환경 변수 검증
name: Deploy
on: [push]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Validate secrets
run: |
if [ -z "${{ secrets.POST_API_KEY }}" ]; then
echo "ERROR: POST_API_KEY is not set"
exit 1
fi
if [ -z "${{ secrets.DB_PASSWORD }}" ]; then
echo "ERROR: DB_PASSWORD is not set"
exit 1
fi
echo "✓ All required secrets are set"
이 단계가 실패하면, workflow도 실패한다. 환경 변수 누락을 빨리 발견할 수 있다.
2단계: Docker 빌드에 명시적으로 전달
- name: Build Docker image
run: |
docker build \
--build-arg POST_API_KEY=${{ secrets.POST_API_KEY }} \
--build-arg DB_PASSWORD=${{ secrets.DB_PASSWORD }} \
-t myapp:latest .
빌드 arg로 전달하면, 나중에 런타임에 누락되는 것과 구분할 수 있다.
3단계: 배포 후 헬스 체크
- name: Health check
run: |
sleep 5
curl -f http://localhost:3000/health || exit 1
배포 직후 앱이 정말 작동하는지 확인한다.
체크리스트 자동화
Python 스크립트로 필요한 secrets을 자동 검증할 수 있다.
#!/usr/bin/env python3
import os
import sys
REQUIRED_SECRETS = [
'POST_API_KEY',
'DB_PASSWORD',
'JWT_SECRET',
'AWS_ACCESS_KEY_ID',
'AWS_SECRET_ACCESS_KEY',
]
missing = [s for s in REQUIRED_SECRETS if not os.environ.get(s)]
if missing:
print(f"ERROR: Missing secrets: {', '.join(missing)}")
sys.exit(1)
print("✓ All required secrets are present")
- name: Check required secrets
run: |
python3 check_secrets.py
env:
POST_API_KEY: ${{ secrets.POST_API_KEY }}
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
Repository 복제할 때
다른 repository로 복제하면 모든 secrets을 다시 설정해야 한다.
# 현재 repository의 secrets 확인
gh secret list
# 다른 repo로 복제
gh secret list -R other/repo
# 수동으로 설정
gh secret set POST_API_KEY -b $POST_API_KEY -R other/repo
GitHub CLI를 쓰면 더 쉽게 관리할 수 있다.
로그에서 secret 누수 주의
Secret을 로그에 출력하면 안 된다. GitHub Actions는 자동으로 마스킹하지만, 실수하기 쉽다.
# 나쁜 예
- run: echo "Database password is ${{ secrets.DB_PASSWORD }}"
# → 로그에 password가 노출될 수 있음
# 좋은 예
- run: echo "Database connected"
# secret은 쓰되, 로그엔 출력하지 않음
만약 실수로 secret을 로그에 출력했다면:
- GitHub에서 secret을 즉시 변경
- Workflow 실행 로그 삭제
- 외부에 노출되지 않았는지 확인
모니터링
배포 후 실제로 앱이 환경 변수를 읽는지 모니터링하자.
// Node.js
if (!process.env.POST_API_KEY) {
console.error('CRITICAL: POST_API_KEY is not set!');
process.exit(1);
}
앱 시작 시점에 모든 필수 환경 변수를 검증하면, 누락된 걸 빨리 발견한다.
정리
Secret 누락은 CI 관점에서는 "성공"이지만, 실제로는 배포 실패다. Workflow에 검증 단계를 추가해서 조기에 발견하자. 특히 새 repository를 만들거나 팀원이 추가될 때 secret 설정을 빼먹기 쉬우므로, 체크리스트를 만들어두는 게 좋다. 일단 배포되면 고치기가 훨씬 어렵다.