해당 글은 프로젝트에서 민간한 정보인 API KEY 를 안전하게 관리하는 방법입니다.
제가 회사에서 한창 개발 중이었던 'AI 음성 주문 시스템'에서 시작되었습니다. 이 시스템은 아직 내부 테스트(QA) 단계에만 배포된 베타 서비스였는데요. AI 기능을 구현하기 위해 OpenAI API 키를 비롯한 여러 키 값들을 .env 파일에 넣어두고 프로젝트를 진행하고 있었습니다.
며칠전에 QA 환경에서 AI 서비스가 동작하지 않는다는 보고를 받았습니다. 의아한 마음에 OpenAI 대시보드에 접속해보니 분명히 존재해야 할 API 키가 사라져 있었습니다. gpt-5가 업데이트 되고 OpenAI 내부에서 모든 api를 삭제한건가..? 라고 생각했어요
저는 대수롭지 않게 생각하고 키를 다시 생성해서 프로젝트에 업데이트한 후 다시 배포했습니다. 서비스는 정상으로 돌아왔습니다.
하지만 다음 날, 똑같은 문제가 다시 발생했습니다. 서비스는 또 멈춰 있었고, 대시보드에 들어가 보니 API 키는 또다시 삭제되어 있었습니다.
해당 이슈에 대해 검색해보고 조금 오래 된 글이지만 OpenAI 커뮤니티에서 "API 키를 Github 저장소에 업로드하면 보안 조치로 인해 자동으로 비활성화" 된다는 글을 봤습니다.
[출처: https://community.openai.com/t/api-key-disappearing-from-my-account/320868]

바로 `.gitignore` 파일을 확인해 보았습니다.
# .gitignore
# ... other ignored files
# .env
# .env.*
`.env` 관련 파일을 Git 추적에서 제외하는 규칙이 주석 처리되어 있었던 것입니다. 실서비스가 아니라는 안일한 생각에, 민감한 API 키가 담긴 `.env` 파일을 그대로 GitHub 저장소에 커밋하고 있었던 겁니다. OpenAI의 보안 시스템이 이를 감지하고 매일 저희의 키를 무효화시켰던 것 같아요 😂
이 경험을 통해 '베타'나 '내부용'이라는 이름 뒤에 숨어 보안을 등한시하는 것이 얼마나 위험한 일인지 깨달았고, 단순히 `.gitignore` 를 수정하는 것을 넘어, "애초에 민감 정보를 코드 저장소에 두지 말자"는 근본적인 해결책을 도입하기로 결정했습니다.
GitHub Actions를 이용한 동적 API 키 주입
'코드 저장소에서는 민감 정보를 완전히 제거하고, 배포(CI/CD) 과정에서만 안전하게 주입하는 것'을 적용했습니다.
GitHub Actions를 사용하고 있었기에, GitHub Secrets 를 활용한 동적 환경 변수 주입 방식을 도입하기로 했습니다.
1단계: 민감 정보 GitHub Secrets로 이전
가장 먼저, `.env` 파일에 있던 모든 API 키와 시크릿 키를 GitHub 저장소의 Secrets로 옮겼습니다.
방법 : New repository secret 버튼을 눌러 각 키를 등록했습니다.

여기서 중요한 점 은, Vite에서는 `VITE_ `접두사가 붙은 환경 변수만 코드에서 접근할 수 있지만, GitHub Secrets에 등록할 때는 접두사 없이 `OPENAI_API_KEY` 와 같이 순수한 키 이름만 등록했다는 것입니다. 접두사는 나중에 CI/CD 파이프라인에서 붙여줄 것입니다.
2단계: GitHub Actions 워크플로우 수정
다음으로, 배포 워크플로우 파일( /.github/workflows/deploy-develop.yml )을 수정하여 빌드 과정 직전에 GitHub Secrets의 값을 읽어와 .env 파일을 동적으로 생성하는 단계를 추가했습니다.
수정 전 워크플로우 (일부):
# ...
- name: Install Dependencies
run: yarn install --immutable
- name: Build
run: yarn build:dev
# ...
수정 후 워크플로우 (일부):
# ...
- name: Install Dependencies
run: yarn install --immutable
- name: Create .env file
run: |
echo "VITE_OPENAI_API_KEY=${{ secrets.OPENAI_API_KEY }}" >> .env.development
...
- name: Build
run: yarn build:dev
# ...
새로 추가된 Create .env file 단계는 다음과 같은 역할을 합니다.
1. GitHub Actions가 제공하는 가상 서버 환경(Runner)에서 작업을 시작합니다.
2. echo 명령어를 통해 VITE_ 접두사를 붙인 환경 변수 이름과 ${{ secrets.KEY_NAME }} 구문을 사용하여 GitHub Secrets에 저장된 값을 조합합니다.
3. 이 내용을 .env.development 파일에 동적으로 생성합니다.
4. 이후 실행되는 Build 단계에서는 이 .env.development 파일을 참조하여 API 키가 포함된 상태로 코드를 빌드합니다.
5. 워크플로우가 종료되면, 이 가상 서버와 그 안에서 생성된 .env.development 파일은 자동으로 파기됩니다.
이 과정을 통해 민감 정보는 오직 배포가 실행되는 순간에만, 통제된 환경에서 잠시 사용되고 영구적으로 남지 않게 됩니다.
3단계: 저장소 정리
마지막으로, 프로젝트에서 민감 정보의 흔적을 완전히 지웠습니다.
1. 로컬과 원격 저장소의 모든 .env.* 파일에서 실제 키 값을 제거했습니다. (개발자 편의를 위해 파일 형식은 남겨두되, 내용은 비워두거나 예시 값으로 대체)
2. `.gitignore` 파일의 주석을 풀어 .env 관련 파일들이 다시는 커밋되지 않도록 확실히 조치했습니다.
결과
이러한 일련의 과정을 통해 저희 프로젝트는 다음과 같은 긍정적인 효과를 얻었습니다.
1. 보안 강화 : API 키가 더 이상 코드 저장소에 존재하지 않으므로, Git 히스토리를 통한 유출 가능성이 원천적으로 차단되었습니다. 이제 민감 정보 접근은 GitHub 저장소의 권한을 통해 통제됩니다.
2. 환경 관리 효율성 증대 : 개발자가 더 이상 여러 환경의 .env 파일을 수동으로 관리하거나 복사할 필요가 없어졌습니다. 모든 환경 변수는 CI/CD 파이프라인을 통해 자동으로 관리되므로 휴먼 에러의 가능성이 줄었습니다.
3. 개발 환경의 안정성 : 로컬 개발 환경에서는 실제 운영 키가 아닌, 개발용 키나 모의(mock) 데이터를 사용하도록 구성할 수 있게 되어 개발자의 실수로 인한 사고를 예방할 수 있습니다.
마치며
소프트웨어 개발에서 보안은 '한 번 하고 끝내는 것'이 아니라 '지속적으로 개선해나가는 과정'이라고 생각합니다. .env 파일을 사용하는 것이 편리하기는 하지만, 그 편리함이 때로는 큰 보안 위협으로 돌아올 수 있다는 점을 이번 경험을 통해 다시 한번 깨달았습니다.
프론트엔드에서도 API 키나 다른 민감 정보를 코드와 함께 관리하고 있다면 GitHub Actions Secrets나 다른 CI/CD 도구가 제공하는 보안 기능을 활용하여 개선하는게 중요한 것 같습니다.
'frond-end' 카테고리의 다른 글
| Vite manualChunks로 웹사이트 로딩 속도 2배 빠르게 만들기(rollup-plugin-visualizer 로 분석 리포트 시각화) (2) | 2025.08.01 |
|---|---|
| AWS S3 + CloudFront 프론트엔드 배포 환경 구성 (5) | 2025.05.22 |
| 가상스크롤 vue-virtual-scroller 활용한 대량 데이터 테이블 성능 최적화 (1) | 2025.05.12 |
| 웹페이지 로딩 지연 시 사용자 경험 개선을 위한 Skeleton UI 구현 (3) | 2025.04.01 |
| GitHub Actions를 이용한 ChatGPT 기반 자동 코드 리뷰 기능 추가하기 (1) | 2025.01.07 |