문제: 흩어진 시크릿, 불안한 마음
1인 개발자로 여러 프로젝트를 운영하다 보면 .env 파일, SSH 키, API 키, 인증서가 곳곳에 흩어진다. contents-hub의 DB 비밀번호, econipass의 Keycloak 시크릿, church-finance의 Gmail SMTP 키... 이 파일들이 한순간에 날아간다면?
맥북이 고장 나거나, 실수로 rm -rf를 때리거나, SSD가 뻗거나. 시크릿은 코드와 달리 Git에 올릴 수 없다. 그래서 별도의 백업 파이프라인이 필요했다.
설계 원칙
- 암호화 필수 — 클라우드에 평문 시크릿을 올리면 안 된다
- 자동화 가능 — 명령 하나로 전체 백업이 되어야 한다
- 보존 정책 — 무한정 쌓이면 안 되고, 최근 5개만 유지
- 복원 가능 — 백업이 있어도 복원이 어려우면 무용지물
도구 선택
rclone — 클라우드용 rsync
rclone은 40개 이상의 클라우드 스토리지를 커맨드라인에서 다루는 도구다. "rsync for cloud storage"라는 별명답게, 로컬 파일을 Google Drive, S3, Dropbox 등에 업로드/다운로드/동기화할 수 있다.
brew install rclone # macOS
sudo apt install rclone # Ubuntu
# Google Drive remote 설정 (1회)
rclone config create gdrive drive \
client_id="..." client_secret="..."
설정 후에는 이렇게 쓴다:
rclone copy local-file gdrive:secrets-backup/ # 업로드
rclone copy gdrive:secrets-backup/file ./ # 다운로드
rclone lsf gdrive:secrets-backup/ # 목록
rclone delete gdrive:secrets-backup/old-file # 삭제
gpg — AES-256 대칭 암호화
gpg의 --symmetric 모드를 사용하면 패스프레이즈 하나로 파일을 AES-256 암호화할 수 있다. 키 쌍을 관리할 필요 없이 패스프레이즈만 기억하면 된다.
# 암호화
gpg --symmetric --cipher-algo AES256 secrets.tar.gz
# → secrets.tar.gz.gpg 생성 (패스프레이즈 입력)
# 복호화
gpg --output secrets.tar.gz --decrypt secrets.tar.gz.gpg
파이프라인 구조
전체 흐름은 이렇다:
[secrets-index.md] 인덱스 파일에서 경로 추출
↓
[staging 디렉토리] 프로젝트별로 파일 복사
↓
[tar.gz] 하나의 아카이브로 압축
↓
[tar.gz.gpg] AES-256 암호화
↓
[Google Drive] rclone으로 업로드
↓
[보존 정책] 최근 5개만 유지, 나머지 자동 삭제
↓
[로컬 정리] 임시 파일 삭제
시크릿 인덱스가 핵심
백업 대상을 자동 탐색하지 않는다. secrets-index.md에 수동으로 등록된 파일만 백업한다. 이유는 명확하다:
- 자동 탐색은 불필요한 파일을 포함할 위험이 있다
- 어떤 시크릿이 어디에 있는지 한눈에 파악할 수 있다
- 프로젝트가 추가되면 인덱스에 한 줄 추가하면 끝이다
스테이징 디렉토리 구조
~/elon/secrets-backup/2026-02-16/
├── projects/
│ ├── contents-hub/ .env, docker-compose.yml, docker-compose.prod.yml
│ ├── econipass/ .env.local, docker-compose.yml, docker-compose.prod.yml
│ ├── church-finance/ .env, gdrive_config.py
│ └── linked-insight/ .env
├── infra/
│ ├── ssh-keys/ .pem, .crt, .csv
│ ├── tccli/ default.credential
│ └── credentials/ gdrive-credentials.json, gdrive-token.json
└── manifest.json 복원에 필요한 원본 경로 매핑
manifest.json이 중요하다. 백업 파일의 상대 경로와 원본 절대 경로를 매핑해두어, 복원할 때 각 파일이 어디로 돌아가야 하는지 알 수 있다.
Claude Code에서의 한계와 해결
한 가지 걸림돌이 있었다. gpg의 패스프레이즈 입력은 대화형(interactive) pinentry를 사용하는데, Claude Code의 비대화형 터미널에서는 이게 동작하지 않는다.
해결책: 2단계 분리
- Claude Code가 하는 일 — 파일 수집, 스테이징, tar 압축, 실행 스크립트 생성
- 사용자가 별도 터미널에서 하는 일 — 스크립트 실행 (gpg 패스프레이즈 입력 → 암호화 → 업로드)
# Claude Code가 생성하는 스크립트
bash ~/elon/secrets-backup/backup-upload.sh
이 방식으로 자동화할 수 있는 부분은 최대한 자동화하고, 패스프레이즈 입력이라는 보안상 불가피한 수동 단계만 사용자에게 맡긴다.
복원 흐름
복원도 동일한 2단계 패턴을 따른다:
- Claude Code가 복원 스크립트 생성 → 사용자가 실행 (다운로드 + gpg 복호화)
- Claude Code가
manifest.json을 읽고, 파일별로 diff 비교 후 복원
이미 존재하는 파일은 diff를 보여주고 덮어쓸지 확인한다. 없는 파일은 바로 복원하고 chmod 600으로 권한을 설정한다.
정리
| 구성 요소 | 역할 |
|---|---|
secrets-index.md |
어떤 시크릿이 어디에 있는지 (Single Source of Truth) |
tar |
여러 파일을 하나로 묶기 |
gpg --symmetric |
AES-256 패스프레이즈 암호화 |
rclone |
Google Drive 업로드/다운로드 |
manifest.json |
원본 경로 매핑 (복원용) |
| 보존 정책 | 최근 5개만 유지 |
비용: 0원. Google Drive 무료 15GB면 시크릿 백업에는 차고 넘친다.
하나의 명령(/secrets backup)으로 모든 프로젝트의 시크릿을 암호화해서 클라우드에 올린다. 맥북이 내일 당장 고장 나도, 새 맥에서 /secrets restore 한 번이면 모든 시크릿이 제자리로 돌아온다. 그게 이 파이프라인의 전부다.