.env 보안 동기화 패턴
핵심 원칙
┌─────────────────────────────────────────────────┐
│ 값 (secret) → macOS Keychain │
│ + iCloud Keychain (자동 sync) │
│ │
│ 키 목록 (참조) → ainote ({project}-env-ref.md) │
│ │
│ ❌ 값 자체를 ainote 에 저장 금지 │
│ ❌ git 에 .env 커밋 금지 │
└─────────────────────────────────────────────────┘왜 이 분리
| 저장소 | 보안 | 동기화 | 검색 |
|---|---|---|---|
| ainote 에 값 | 약함 (키 노출 위험) | ✅ | ✅ |
| Keychain 만 | 강함 (OS 암호화) | ✅ iCloud | ❌ |
| Keychain + ainote 참조 | 강함 | ✅ | ✅ (참조만) |
ainote 는 어떤 키가 어디 있는지만 — 실제 값은 Keychain.
스크립트 사용
~/scripts/ainote-env-sync.sh (설치 가이드).
Push: .env → Keychain + ainote 참조
bash
ainote-env-sync.sh push tennis-bracket내부 동작:
~/tennis_bracket/.env읽음- 각 KEY=VALUE 를
security add-generic-password로 Keychain 저장- service:
dev-env/tennis-bracket - account: KEY 이름
- service:
- 키 목록 (이름만) 을 ainote 에
tennis-bracket-env-ref.md로 push
Pull: Keychain → .env (새 기기)
bash
ainote-env-sync.sh pull tennis-bracket내부 동작:
- ainote 에서
tennis-bracket-env-ref.md받음 → 키 목록 - 각 키를
security find-generic-password로 Keychain read ~/tennis_bracket/.env생성
ainote 에 저장되는 형식
tennis-bracket-env-ref.md:
markdown
---
name: tennis-bracket-env-ref
type: reference
ainote_sync: env-refs/tennis-bracket-env-ref.md
last_pushed: 2026-05-07T10:00:00Z
device: macmini-2026-04
---
# tennis-bracket .env Reference
| Key | Type | Source | Note |
|-----|------|--------|------|
| RAILS_ENV | config | env | development/production |
| DATABASE_URL | secret | Keychain | postgres URL |
| TOSS_CLIENT_KEY | secret | Keychain | TossPayments client |
| TOSS_SECRET_KEY | secret | Keychain | TossPayments secret |
| FIREBASE_PROJECT_ID | config | env | tennis-bracket-app |
| AWS_ACCESS_KEY_ID | secret | Keychain | S3 |
| ... | ... | ... | ... |값 없음. 이름 + 타입만.
새 기기 일괄 복원 (5분)
bash
# 1. iCloud Keychain 켜기 (시스템 설정)
# 2. 스크립트 받기
brew install ainote-tools
# 3. ainote 키
export AINOTE_API_KEY="..."
# 4. 일괄
ainote-env-sync.sh pull-all응답:
✓ ~/launchcrew/.env (18 keys from Keychain)
✓ ~/tennis_bracket/.env (12 keys)
... (12 projects)
✅ 12 .env files restored키 회전
분기마다:
bash
# 1. 새 키 발급 (서비스 사이트)
TOSS_SECRET_KEY="<NEW>"
# 2. .env 수정
$EDITOR ~/tennis_bracket/.env
# 3. push (Keychain 갱신 + ainote ref 갱신 — last_pushed 만 변경)
ainote-env-sync.sh push tennis-bracket비밀 누출 시
bash
# 1. Keychain 즉시 삭제
security delete-generic-password -s "dev-env/tennis-bracket" -a "TOSS_SECRET_KEY"
# 2. ainote 참조에서도 표시
$EDITOR ~/tennis_bracket/.env # KEY 자체 삭제
ainote-env-sync.sh push tennis-bracket서비스 콘솔에서 키 폐기 + 새 발급.
등록된 프로젝트 (예시)
bash
$ ainote-env-sync.sh list
tennis-bracket 12 keys Last sync: 2026-05-07
launchcrew 18 keys Last sync: 2026-05-06
keeps 8 keys Last sync: 2026-05-05
triphelper 15 keys
realpick 9 keys
talkk 14 keys
ax-admin 22 keys
ainote-app 11 keys
krx-listing 19 keys
krx-ai 13 keys
mbti-luck 7 keys
forfit 6 keys비교: 다른 솔루션
| ainote-env-sync | 1Password CLI | doppler | direct iCloud | |
|---|---|---|---|---|
| iCloud Keychain | ✅ free | △ | ❌ | ✅ |
| 키 목록 검색 | ✅ ainote | ✅ | ✅ | ❌ |
| 무료 | ✅ | △ | ⚠️ free tier | ✅ |
| 프로젝트별 .env | ✅ | △ vault | ✅ env | ❌ |
| 자동화 친화 | ✅ shell | ✅ CLI | ✅ CLI | ❌ |