OpenBao 자동 언실
OpenBao(dev/prod 클러스터의 시크릿 저장소)가 재시작할 때 사람 개입 없이 unseal 되는 구조를 정리한다. 언실 서버는 모노레포의 cone-watcher-openbao-unsealer/(Cloudflare Worker, https://bao-unseal.conecloud.io)이며, 클러스터 밖에 있어서 클러스터 전체가 내려갔다 올라와도 자동 언실이 동작한다.
핵심: 진짜 Vault transit 엔진이 아니라, OpenBao seal "transit" 클라이언트가 호출하는 API 부분집합만 구현한 shim이다. 토큰 갱신(lease) 엔드포인트가 없으므로 OpenBao 쪽 seal 스탠자에 disable_renewal = "true" 가 필수다 (cone-watcher-gitops/argocd/infra/openbao.yaml).
1. 언실 흐름
encrypt는 init/rekey 시점에 root key 블롭을 만들 때 호출된다. 이후 재시작마다 위의decrypt만 탄다.- 클러스터별로 키 이름과 토큰이 분리되어 있다(
autounseal-dev/autounseal-prod). dev 토큰이 유출돼도 prod 키는 못 쓴다.
2. Worker가 구현한 API 표면
에러는 항상 Vault 표준 포맷 {"errors":["..."]} 으로 내려간다 — 이 포맷이어야 seal 클라이언트가 메시지를 그대로 로그에 보여준다.
3. ciphertext 포맷과 키 버전
- 암호화는 항상 최신 버전 키, 복호화는 ciphertext에 박힌 vN 버전 키를 쓴다.
- 그래서 키 로테이션은
UNSEAL_KEYS에 다음 버전을 추가하고 재배포하면 끝 — 구버전으로 만든 기존 블롭도 계속 풀린다. 구버전 제거는 OpenBao가 새 버전으로 재암호화(재시작 또는 seal rewrap)한 뒤에만 가능하다.
4. 코드 구조 (src/index.ts 단일 파일)
위에서 아래로 읽으면 되는 구조로, HTTP 셸과 암호화 코어가 분리되어 있다.
- 실패는 전부
HttpError(status, message)throw 로 처리한다. 핸들러 곳곳에서 에러 Response를 만들지 않고,fetch의 catch 한 곳에서만 Vault 에러 포맷으로 변환한다.HttpError가 아닌 예외(시크릿 설정 오류 등)는 그대로 던져져 Workers가 500으로 처리한다. - 암호화 코어 함수들은
Response를 모른다. 키링(버전 → base64 키)과 데이터만 받아 데이터를 리턴하므로 HTTP 없이 단독 테스트할 수 있다.
5. 시크릿 구조
UNSEAL_KEYS 를 잃으면 모든 OpenBao를 recovery key로만 복구할 수 있으므로, 키 JSON 원본은 패스워드 매니저에 별도 보관한다.
6. 운영 작업 (상세는 각 문서)
빠른 동작 확인: