본문 바로가기

frond-end

API 키 안전하게 관리하기: GitHub Actions Secrets와 CI/CD 동적 환경 변수 주입

반응형

해당 글은 프로젝트에서 민간한 정보인 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로 옮겼습니다.

 

위치: GitHub Repository > Settings > Secrets and variables > Actions

방법 : 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 도구가 제공하는 보안 기능을 활용하여 개선하는게 중요한 것 같습니다.


728x90
반응형