개발 키가 많아질수록: Bitwarden으로 비밀번호와 시크릿을 나누는 법
서비스를 운영하다 보면 GitHub 토큰, 데이터베이스 비밀번호, API 키, 배포 인증서, 백업 암호화 키가 빠르게 늘어납니다. 처음에는 비밀번호 관리 앱의 메모나 여러 .env 파일에 저장해도 괜찮아 보이지만, 키가 많아질수록 “무엇이 최신인지”, “개발용인지 운영용인지”, “어디에서 사용 중인지”를 판단하기 어려워집니다.
이 문제의 핵심은 저장 공간이 부족한 것이 아닙니다. 사람이 사용하는 로그인 정보와 프로그램이 사용하는 비밀정보를 같은 방식으로 관리하는 데서 혼란이 시작됩니다. 이 글에서는 Bitwarden Password Manager와 Bitwarden Secrets Manager의 역할을 나누고, 개발 환경과 자동화 작업에서 키를 안전하게 사용하는 방법을 정리합니다.
먼저 사람용 계정과 프로그램용 시크릿을 나눕니다
| 구분 | 대표 사례 | 적합한 저장소 |
|---|---|---|
| 사람이 로그인할 때 사용하는 정보 | GitHub·Cloudflare·호스팅 관리자 계정, 패스키 | Bitwarden Password Manager |
| 프로그램이 실행 중 사용하는 정보 | DATABASE_URL, API 토큰, 애플리케이션 시크릿 |
Bitwarden Secrets Manager |
| 과거 데이터 복구에 필요한 정보 | 백업 암호화 키, 인증서 복구 정보 | Secrets Manager와 별도 복구 사본 |
Password Manager는 사람이 브라우저나 앱에서 로그인할 때 편리합니다. 반면 Secrets Manager는 애플리케이션, 배포 파이프라인, 백업 작업처럼 사람이 아닌 실행 주체가 필요한 값만 가져가도록 설계되어 있습니다.
두 제품을 나누어 사용하면 운영 비밀번호를 매번 복사해 붙여 넣는 일이 줄고, 특정 자동화 계정이 읽을 수 있는 범위를 제한할 수 있습니다.
폴더보다 먼저 저장 원칙을 정합니다
Password Manager의 폴더는 개인 금고를 보기 좋게 정리하는 용도입니다. 팀과 항목을 공유하거나 접근 권한을 관리하려면 Organization의 Collection을 사용해야 합니다. 폴더에 넣었다고 공유 권한이 바뀌지는 않습니다.
개인 금고는 다음 정도로 단순하게 유지하는 편이 좋습니다.
Work/
├─ Console
├─ Cloud-Domain
├─ Server
├─ Recovery
└─ Archive사람이 직접 입력하는 관리자 계정은 이 구조에 저장하고, 데이터베이스 접속 문자열이나 API 키는 Secrets Manager로 이동합니다. 로그인 항목과 개발 시크릿이 검색 결과에서 뒤섞이지 않는 것만으로도 관리 부담이 크게 줄어듭니다.
Secrets Manager는 프로젝트와 환경을 기준으로 나눕니다
시크릿 이름 앞에 모든 정보를 길게 붙이기보다 프로젝트 자체를 환경별로 구분하는 방식이 명확합니다.
product-dev
├─ DATABASE_URL
├─ AUTH_SECRET
└─ EXTERNAL_API_TOKEN
product-prod
├─ DATABASE_URL
├─ AUTH_SECRET
└─ EXTERNAL_API_TOKEN
product-backup
├─ BACKUP_ENCRYPTION_KEY_V1
└─ BACKUP_STORAGE_PASSWORD개발과 운영에서 이름은 같아도 실제 값은 반드시 분리해야 합니다. 이렇게 하면 코드에서는 표준 환경변수 이름을 그대로 사용하면서도 프로젝트 권한으로 환경을 구분할 수 있습니다.
Secret의 메모에는 값 대신 다음과 같은 운영 정보만 남기는 것이 좋습니다.
용도: 운영 데이터베이스 접속
발급처: 데이터베이스 관리 시스템
사용처: production 배포 작업
담당자: 운영 담당자
생성일: YYYY-MM-DD
교체 조건: 노출 의심, 접근자 변경 또는 만료
관련 작업: deploy workflowMachine Account에는 필요한 권한만 부여합니다
Machine Account는 애플리케이션이나 자동화 파이프라인을 위한 계정입니다. 사람의 Bitwarden 로그인 정보를 자동화에 넣는 대신, 용도별 Machine Account를 만들고 필요한 프로젝트의 읽기 권한만 부여합니다.
github-actions-deploy → product-prod 읽기
github-actions-backup → product-backup 읽기
developer-local → product-dev 읽기배포 계정이 백업 암호화 키를 읽거나 개발 환경이 운영 데이터베이스에 접근하지 못하도록 경계를 만드는 것이 중요합니다. 토큰이 노출되더라도 접근 범위를 줄일 수 있고, 문제가 발생한 계정만 폐기할 수도 있습니다.
로컬 .env 파일은 임시 산출물로 취급합니다
로컬 개발에서는 .env 파일을 계속 복사하기보다 Secrets Manager CLI로 실행 시점에 값을 주입할 수 있습니다.
bws run --project-id <PROJECT_ID> -- npm run dev이 방식에서는 지정한 프로젝트의 Secret이 프로세스 환경변수로 전달됩니다. 저장소에는 값이 없는 .env.example만 두고, 필요한 변수 이름과 설명만 기록하면 실수로 비밀값을 커밋할 가능성을 줄일 수 있습니다.
GitHub Actions도 실행할 때 시크릿을 가져옵니다
Bitwarden은 GitHub Actions용 공식 연동을 제공합니다. GitHub에는 실제 데이터베이스 비밀번호나 백업 키 대신, 범위가 제한된 Machine Account 접근 토큰을 저장합니다.
- name: Load secrets
uses: bitwarden/sm-action@v2
with:
access_token: ${{ secrets.BW_ACCESS_TOKEN }}
secrets: |
<SECRET_ID> > DATABASE_URL
- name: Run migration
run: npm run migrate가져온 값은 후속 작업의 환경변수로 사용합니다. 접근 토큰도 비밀정보이므로 GitHub Secret에 보관하고, 만료일과 접근 프로젝트를 제한해야 합니다.
백업 암호화 키는 덮어쓰지 않고 버전으로 관리합니다
일반 API 토큰은 교체 후 이전 값을 폐기할 수 있지만, 암호화 키는 과거 백업을 해독할 때 다시 필요합니다. 기존 값을 같은 이름으로 덮어쓰면 정상적인 백업까지 복구하지 못할 수 있습니다.
BACKUP_ENCRYPTION_KEY_V1 → 기존 백업용
BACKUP_ENCRYPTION_KEY_V2 → 신규 백업용신규 백업은 V2로 생성하되, V1로 암호화된 백업의 보존 기간이 끝날 때까지 V1도 유지해야 합니다. 키 버전과 백업 파일의 관계를 운영 문서에 기록하되 실제 키 값은 문서에 넣지 않습니다.
비밀값이 없는 시크릿 목록을 운영합니다
Secrets Manager만 열어보아도 값을 찾을 수 있지만, 어떤 시스템이 어떤 키에 의존하는지 설명하는 목록은 별도로 필요합니다. 운영 문서에는 다음 항목만 기록합니다.
| 키 이름 | 환경 | 원본 저장소 | 사용처 | 교체 조건 |
|---|---|---|---|---|
DATABASE_URL |
production | Secrets Manager | 웹 애플리케이션 | 접속 정보 변경 |
BACKUP_ENCRYPTION_KEY_V1 |
backup | Secrets Manager | 백업·복원 작업 | 보존 기간 종료 후 폐기 |
실제 값은 Bitwarden에만 두고, 문서에는 이름·용도·소유자·사용처만 남기는 것이 핵심입니다. 이 원칙을 지키면 문서 공유 범위와 관계없이 비밀값이 노출되지 않습니다.
Bitwarden 자체의 복구 경로도 준비합니다
중앙 금고가 안전해도 계정에 접근하지 못하면 운영이 중단될 수 있습니다. 다음 항목은 초기 설정과 함께 준비하는 것이 좋습니다.
- 길고 고유한 마스터 패스프레이즈를 사용합니다.
- 2단계 인증을 활성화하고 예비 인증 수단을 준비합니다.
- Bitwarden 복구 코드는 Bitwarden 금고 밖의 안전한 장소에도 보관합니다.
- 암호화된 금고 내보내기를 주기적으로 생성하고 복구 가능 여부를 확인합니다.
- 클립보드 자동 삭제를 활성화합니다.
- 중요한 관리자 계정은 URI 일치 범위를
Host또는Exact로 제한합니다.
복구 코드를 금고 안에만 보관하면 금고에 들어가지 못할 때 코드도 확인할 수 없습니다. 최소 한 개의 복구 수단은 주 금고와 장애 영역이 겹치지 않도록 분리해야 합니다.
한 번에 모두 바꾸지 않고 세 단계로 시작합니다
- Password Manager에서 사람용 로그인과 개발 키를 분류합니다.
- 개발·운영·백업 프로젝트를 만든 뒤 장기 사용 중인 시크릿부터 옮깁니다.
- 로컬 개발과 GitHub Actions에서 실행 시점 주입을 적용합니다.
처음부터 모든 키를 자동화하려고 하면 오히려 누락을 만들 수 있습니다. 백업 암호화 키나 배포 토큰처럼 사용처가 명확한 항목 하나를 골라 저장, 주입, 교체, 복구 과정을 먼저 검증하는 편이 안전합니다.
듀오랩스가 보는 관점
좋은 비밀정보 관리의 목표는 보안 도구를 많이 도입하는 데 있지 않습니다. 비밀값을 사람이 보고 복사하고 전달하는 횟수를 줄이고, 필요한 프로그램이 필요한 순간에 필요한 값만 사용하도록 만드는 데 있습니다.
Password Manager는 사람의 로그인을 맡고 Secrets Manager는 프로그램의 자격 증명을 맡도록 역할을 분리하면, 키가 늘어나도 일관된 기준을 유지할 수 있습니다. 여기에 환경 분리, 최소 권한, 버전 관리, 복구 훈련을 더하면 작은 프로젝트에서도 운영 가능한 시크릿 관리 체계를 만들 수 있습니다.
참고 자료
함께 읽기
- HMAC 입문: 서버는 값이 바뀌었다는 사실을 어떻게 알아낼까?웹 서비스를 만들다 보면 이런 값들을 자주 다룹니다.
- 웹사이트 공개 전 무료 점검 도구: 속도·보안·접근성·SEO 한 번에 확인하기웹사이트는 화면과 기능이 완성됐다고 바로 공개할 수 있는 상태가 되는 것은 아닙니다. 실제 사용자가 느끼는 속도, HTTP 보안 헤더, HTTPS 설정, 키보드 접근성, 구조화 데이터, DNS 설정은 서로 다른 문제입니다.
- DUOLABS AI 기능 탐구 20: 비밀값을 노출하지 않고 연결을 점검하는 키 보관함DUOLABS AI 기능 탐구 스무 번째 글은 API 키 원문을 화면에 노출하지 않고 설정 상태와 공급자 연결을 점검하는 키 보관함입니다.
- HSTS 설정 전 알아야 할 옵션과 안전한 적용 순서HSTS(HTTP Strict Transport Security)는 브라우저에 “이 도메인은 항상 HTTPS로만 접속해야 한다”고 알려주는 보안 정책입니다. 잘 설정하면 중간자 공격과 SSL stripping을 줄일 수 있지만, 성급하게 적용하면 장애 복구가 어려워질 수 있습니다.
- AWS 서비스 10개를 3개로 줄이면 무엇이 달라질까?Next.js로 웹 서비스를 만들 때 AWS 서비스를 하나씩 고르면 꽤 긴 목록이 나온다. CDN, API 입구, 함수 실행, PostgreSQL, 인증, 파일 저장, Redis, Queue, 이벤트 예약, 배포 파이프라인이 각각 다른 서비스다.