Skip to Content

Vaultwarden 복구

AI 요청 프롬프트

https://docs.axelabs.ai/ops/runbook/vault-recovery 따라 axe-vaultwarden 복구 진행해줘. 진행: 1. 현재 증상 진단 — docker ps + curl /identity/.well-known/openid-configuration + 사용자 보고로 시나리오 1~6 중 어느 분기인지 식별 2. 시나리오 식별 후 추가 분기 확인 (PostgreSQL vs SQLite backend / Timshel fork vs mainline / customer 측 axe.axelabs.ai vs realchoice 측) 3. 페이지의 각 명령 실행 + 검증, 매 step 결과 받고 다음. backup 또는 force-recreate 등 destructive 명령 직전 사용자 확인 4. 함정 발생 시 페이지 "함정" 표 따라 우회 (column 명 verifier vs code_verifier / digest pin / 시나리오 6 = 영구 손실 — 복구 불가) 5. 복구 완료 검증 (SSO 로그인 + vault item 조회 + admin endpoint) + 사고 원인 /ops/known-gaps 한 줄 (재발 방지)

본인 AI session = Claude Code / Cursor / ChatGPT 데스크탑 / Claude.app / 기타.

페이지 본문 = 사람이 직접 read 도 가능, AI 도 참고. AI 가 본 페이지 fetch 후 위 진행 순서대로 사용자와 step-by-step interactive 풀어나감.

axe-vaultwarden 서비스가 죽거나 OIDC 가 깨졌을 때.

시나리오 1 — 컨테이너 죽음

docker ps -a | grep vault # axe-vaultwarden Exited (1) # 단순 재시작 cd /Users/axe/.axe/vault docker compose up -d --force-recreate sleep 5 curl -sk https://localhost:8222/identity/.well-known/openid-configuration | head -5

설정 정상이면 정상 가동.

시나리오 2 — OIDC 깨짐 (sso_nonce 누락)

D-ops-12 에서 다룬 알려진 이슈. Timshel fork 가 sso_nonce 테이블을 알아서 생성 안 함. 2026-05-25 정정 (Truvia realchoice 검증) — Timshel fork 의 실제 column 명 = verifier (NOT code_verifier). PostgreSQL / SQLite backend 분기 명령 별도.

증상:

ERROR: relation "sso_nonce" does not exist (PostgreSQL) 또는 sqlite> .schema sso_nonce → empty (SQLite)

PostgreSQL backend (axec axe-vaultwarden 패턴)

docker exec axe-vaultwarden-postgres psql -U vaultwarden -d vaultwarden -c " CREATE TABLE IF NOT EXISTS sso_nonce ( state TEXT PRIMARY KEY, nonce TEXT NOT NULL, verifier TEXT NOT NULL, redirect_uri TEXT NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT NOW() ); " docker compose restart axe-vaultwarden

SQLite backend (soohunkang/vault repo + Vaultwarden 공식 image, 예: realchoice 의 ~/vault)

# vault-app 컨테이너 안의 sqlite3 (또는 host 측에서 docker exec) docker exec vault-app sqlite3 /data/db.sqlite3 <<'EOF' CREATE TABLE IF NOT EXISTS sso_nonce ( state TEXT PRIMARY KEY, nonce TEXT NOT NULL, verifier TEXT NOT NULL, redirect_uri TEXT NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ); EOF # 만약 위 schema 작성 후 column 명 mismatch 로 fail 보이면 (이전에 잘못된 column 이름으로 만든 경우): docker exec vault-app sqlite3 /data/db.sqlite3 "ALTER TABLE sso_nonce RENAME COLUMN code_verifier TO verifier;" docker compose restart vault-app

(db.sqlite3 경로는 DATA_FOLDER env 또는 /data volume mount 기준. compose.yaml 확인 후 적용.)

시나리오 3 — Microsoft SSO 갑자기 안 됨

원인 후보:

  • Vaultwarden app 의 client_secret 만료
  • redirect_uri 등록 잘못됨
  • AZURE_TENANT_ID 또는 AZURE_VAULTWARDEN_APP_ID 잘못 설정

확인:

# .env 검증 cat /Users/axe/.axe/vault/.env | grep -E 'AZURE_(TENANT_ID|VAULTWARDEN)' # 컨테이너 env 검증 docker exec axe-vaultwarden env | grep -E 'SSO_(AUTHORITY|CLIENT)'

해결:

  1. customer IT 측 Azure 에서 새 client_secret 발급
  2. .envAZURE_VAULTWARDEN_CLIENT_SECRET= 새 값으로
  3. docker compose up -d --force-recreate

시나리오 4 — 컨테이너 손상 / 데이터 손실

# 1. backup 확인 restic -r /Users/axe/.axe/backups/local snapshots \ --password-file &lt;(security find-generic-password -w -s axe.backup.restic.local -a axe-cli) \ --tag vault # 2. 가장 신선한 vault snapshot 복원 # `axe restore` 는 Phase 5 stub — 현재는 restic 직접 + docker volume restore: restic -r /Users/axe/.axe/backups/local \ --password-file &lt;(security find-generic-password -w -s axe.backup.restic.local -a axe-cli) \ restore &lt;snapshot_id&gt; --target /tmp/vault-restore --include '/Users/axe/.axe/vault/*' # 그 후 docker volume 또는 .yml volume mount 위치에 복사 # 3. 컨테이너 재시작 cd /Users/axe/.axe/vault docker compose up -d --force-recreate # 4. Microsoft SSO 시도 open https://axe.axelabs.ai/vault

시나리오 5 — Timshel fork 업데이트

Timshel fork 의 새 release 가 나왔을 때.

⚠️ 신중하게. Timshel 은 mainline Vaultwarden 보다 작은 PR queue → 가끔 breaking change.

# 1. 현재 digest pin 확인 grep ghcr.io /Users/axe/.axe/vault/docker-compose.yml # 2. 새 digest 확인 (Timshel 의 GitHub Releases) # https://github.com/Timshel/vaultwarden/releases # 3. 비프로덕션 환경에서 테스트 (있다면) # 4. backup 전체 (vault + DB) # 수동 backup (현재 `axe backup` subcommand 없음 → restic 직접): restic -r /Users/axe/.axe/backups/local \ --password-file &lt;(security find-generic-password -w -s axe.backup.restic.local -a axe-cli) \ backup /Users/axe/.axe/vault --tag vault-pre-upgrade # 5. .yml 의 image: line 갱신 vim /Users/axe/.axe/vault/docker-compose.yml # image: ghcr.io/timshel/vaultwarden@sha256:&lt;new&gt; # 6. 재시작 docker compose up -d --force-recreate # 7. 검증 # - admin 로그인 # - Microsoft SSO 로그인 # - 기존 collection 의 item 조회 # - 새 item 생성/조회 # 8. 실패 시 rollback docker compose down # .yml 의 image: 옛 digest 로 되돌림 docker compose up -d

bw CLI data.json cache stale recovery (운영자 측)

서버 측 복구가 아닌 운영자 본인 머신의 bw CLI 회복 절차. server-side vault patch deploy 후 local data.json cache 가 stale 상태로 잔존하면서 발생.

증상:

[Encrypt service] MAC comparison failed

bw unlock 또는 bw get <name> 시 위 에러 → bw 명령 전체 실패.

언제 발생: server-side vault patch deploy 후 (axe.2 → axe.3 등). bw CLI 의 local data.jsoncryptoSymmetricKey cache 가 옛 schema 의 wrapped key 보유 → 새 server 가 내려준 패치 후 shape 와 mismatch → decrypt 시 MAC mismatch. bw unlock 자체는 cache 무효화 안 함.

빈도: server patch 마다 1회 — 2026-05-22, 2026-05-26 두 차례 재발 확정. patch shape 변경 시 매번.

표준 회복 절차 (운영자 본인 머신, 약 30초):

bw logout bw config server https://axe.axelabs.ai/vault bw login # email + MP + Entra MFA (interactive) bw unlock # MP — session token stdout export BW_SESSION="...token..." bw get password <known-secret> # 검증

이후 Keychain 의 axe.vault.session entry 갱신:

bw unlock --raw | security add-generic-password -s 'axe.vault.session' -a "$(whoami)" -w "$(cat)" -U

자동화 후보 (영구 fix, B-bw-cache-stale-autoheal):

  • axe vault reset 신설 — 위 4단계를 한 명령으로
  • _bw_get_password 헬퍼가 MAC comparison failed 패턴 감지 시 자동 reset + retry
  • axe ship vault post-deploy hook 이 patch shape 변경 시 osascript 알림 — 운영자 본인에게 “logout/login 필요” pre-warn

함정:

함정결과회피
ai@ personal vault 가 약 37 items → fresh login 시 sync 약 30초 대기bw login 직후 bw get 호출 시 일부 item 미반영login 직후 bw sync 명시 + 약 30초 대기
bw loginBW_CLIENTID / BW_CLIENTSECRET env 잔존 시 API key 모드로 진입SSO 흐름과 다른 인증 경로 — 일반 사용 OK 단 본 회복 절차는 interactive 가 가장 안전회복 시 unset BW_CLIENTID BW_CLIENTSECRETbw login
~/.config/Bitwarden CLI/ (또는 $BITWARDENCLI_APPDATA_DIR) 의 data.json 직접 삭제 시도clean state 안 됨 + session token 잔존bw logout 권장 (data.json + session 모두 정리)
Keychain 의 axe.vault.session 옛 token 잔존axe secret * 호출이 옛 invalid session 으로 NO_SESSION_IN_KEYCHAINlogin 후 위 security add-generic-password ... -U 로 갱신 필수

시나리오 6 — 운영자 master password 분실

⚠️ 이건 영구 손실. Vaultwarden 의 master password 는 vault 의 encryption key. 모르면 모든 item 복호화 불가.

회피:

  1. master password 는 종이 메모 + 신뢰할 수 있는 가족 (또는 다른 안전한 곳)
  2. 매월 1회 master password 로 로그인 시도 (잊지 않게)
  3. Bitwarden export 정기 + 그 export 파일 자체도 vault 의 master password 로 암호화

분실 시 — vault 폐기, 모든 item 재발급. 회사 운영 1주일 이상 마비 가능. 그래서 종이 백업 필수.

함정

함정결과회피
Timshel digest pin 안 함 (:latest)무작위 업데이트항상 @sha256:&lt;digest&gt;
backup 안 함sso_nonce 깨졌을 때 복구 불가매일 자동 backup
.env 평문 commitsecret 노출.gitignore + Keychain
master password 단일 보관분실 시 영구 손실종이 + 가족 이중화
분기 drill 안 함restore 절차 실제 검증 안 됨com.axe.restore-drill 자동화
Last updated on