Bitwarden이 조용히 바꾼 것들 – 오픈소스 비밀번호 관리자 2026년 업데이트 정리

목차

CLI 스크립트로 vault에 새 항목을 동기화하다가 bw sync가 갑자기 401을 뱉었다. 토큰 만료겠거니 하고 재로그인했는데 이번엔 Mac failed. 한참 헤매다 보니 클라이언트 KDF 설정이 PBKDF2에서 Argon2id로 자동 마이그레이션돼 있었고, 서버에 저장된 protected symmetric key랑 로컬이 안 맞았던 거다. 이게 Bitwarden이 최근 1년 사이 조용히 바꾼 것 중 하나다.

실제로, 비밀번호 관리자 얘기 나오면 거의 반사적으로 "1Password 써라"가 나온다. UI도 깔끔하고, 가족 공유도 잘 되고, SSH 키 관리까지 통합돼 있으니까. 틀린 말은 아니다. 다만 Bitwarden이 2025년 후반부터 2026년 초까지 바꾼 것들을 보면, "그래도 1Password"라는 통념이 예전만큼 자명하지는 않다. Hacker News에서도 비슷한 톤의 스레드가 몇 차례 올라왔다.

게다가, 이 글은 그 업데이트 목록을 단순히 나열하는 게 아니라, 직접 vault를 self-host하고 CLI/SDK로 자동화 스크립트를 굴려본 경험에서 "이건 진짜로 의미 있는 변화", "이건 마케팅 문구일 뿐"을 구분해보려 한다. 작성 시점은 2026년 5월 기준이고, 버전은 서버 v2026.4.x, 클라이언트 v2026.4.x, SDK v1.0.x를 기준으로 한다.

"오픈소스니까 그냥 무료겠지"라는 통념부터 깨자

가장 흔한 오해다. Bitwarden을 한 번도 안 써본 사람한테 추천하면 열에 일곱은 "어차피 오픈소스니까 다 무료 아니야?"라고 묻는다. 반은 맞고 반은 틀리다.

서버와 클라이언트 본체는 여전히 자유 라이선스(GPL/AGPL 계열)다. self-host도 가능하고, Vaultwarden 같은 비공식 Rust 재구현체도 활발하다. 그런데 2024년 말~2025년 사이 Bitwarden은 Password Manager SDK의 라이선스를 변경했다. 일부 코드가 SDK 내부로 옮겨가면서, 클라이언트 빌드 시 의존하는 SDK는 자체 라이선스(Bitwarden License v1.0)로 묶였다. GitHub 이슈 #15124 근처에서 이 논쟁이 크게 붙었다.

또한, 핵심은 이거다. 개인이 self-host해서 vault만 굴리는 건 여전히 자유롭다. 다만 "Bitwarden 클라이언트를 fork해서 다른 이름으로 배포하고 그 안에서 vault 암복호화를 수행"하려면 SDK 라이선스 조건을 따져야 한다. 실용적으로는 99%의 사용자한텐 영향이 없지만, "그냥 오픈소스니까 다 자유"라는 단순화는 더 이상 맞지 않다.

Vaultwarden과의 호환성은 어떻게 됐나

게다가, self-host 진영의 절반은 사실 공식 서버가 아니라 Vaultwarden을 쓴다. 컨테이너 한 줄로 띄울 수 있고, Rust 단일 바이너리라 메모리도 가볍다. 8GB짜리 작은 VPS에서도 잘 돈다.

그래서, 문제는 SDK 변경 이후 일부 신규 기능이 공식 클라이언트에서만 동작한다는 거다. 예를 들어 패스키(passkey) 관련 일부 흐름, SSH agent 통합, 새 export 포맷 같은 것들. Vaultwarden 측은 호환 레이어를 따라잡고 있지만 한두 버전씩 뒤처지는 게 일상이 됐다. 이걸 두고 "Vaultwarden은 죽었다"라고 단정하는 글도 많은데, 실제로 Vaultwarden 1.34.x 릴리즈 노트를 보면 아직 활발하다. 단 "공식과 100% 동일"한 시기는 끝났다고 보는 게 정확하다.

직접 운영하는 입장에서 체감되는 변화는 단순하다. 예전엔 vaultwarden 컨테이너 띄우고 잊고 살았다면, 이제는 클라이언트 메이저 업데이트 직후 한 번씩은 동작 확인이 필요하다. 자동 업데이트를 끄고 한 사이클 묵혀서 적용하는 패턴으로 바꿨다.

Argon2id 기본화 — 이게 생각보다 크다

KDF(Key Derivation Function) 얘기는 보안 블로그에선 매번 나오지만 일반 사용자한테는 추상적인 단어다. 그래도 이번 변화는 실제로 vault를 다 다시 풀고 다시 잠가야 하는 변화라서 짚고 넘어가야 한다.

PBKDF2에서 Argon2id로 바뀐 맥락

Bitwarden은 오래된 vault일수록 KDF가 PBKDF2-SHA256, iteration 100,000~600,000 정도로 박혀 있다. PBKDF2는 GPU/ASIC 공격에 상대적으로 약하다는 게 알려진 지 오래됐고, OWASP도 신규 시스템엔 Argon2id를 권장한다.

Bitwarden은 2023년에 Argon2id를 지원하기 시작했고, 2024~2025년에 걸쳐 신규 계정의 기본값을 Argon2id로 전환했다. 그리고 2026년 들어서는 일정 조건의 기존 계정도 마스터 패스워드 변경 시 자동으로 Argon2id로 마이그레이션된다. 이게 위에서 말한 401 사건의 원인이었다.

항목 PBKDF2-SHA256 (구) Argon2id (현 기본)
iteration / time cost 600,000 3
memory 무관 64 MiB
parallelism 1 4
GPU 저항성 약함 강함
모바일 영향 작음 메모리 64MB 필요

반면, 체감 차이는 로그인할 때 1초 정도 더 걸린다는 것 정도다. 단 오래된 안드로이드 폰이나 메모리가 빠듯한 환경에서는 unlock이 미세하게 무거워진다. 4GB 램의 구형 폰에서 다른 앱 여러 개 띄워두면 unlock 직후 다른 앱이 한 번씩 죽는 걸 봤다. 실사용에 큰 지장은 아니지만 의외였다.

자동 마이그레이션의 함정

실제로, CLI 스크립트로 vault를 다루는 사람이라면 한 번쯤 부딪힐 부분이다. 클라이언트가 Argon2로 KDF를 바꾸면 protected symmetric key가 새 키로 다시 wrap된다. 그 사이 다른 디바이스의 캐시된 세션은 invalid해진다. bw sync가 401을 뱉는 시나리오가 이거다.

# 401이 떴을 때 가장 확실한 복구 순서
bw logout
bw config server https://vault.example.com  # self-host인 경우
bw login --apikey                            # 환경변수 BW_CLIENTID/SECRET 사용
export BW_SESSION=$(bw unlock --raw --passwordenv BW_PASSWORD)
bw sync

--apikey 로그인을 쓰면 SSO 흐름이나 2FA 인터랙션을 우회할 수 있어서 CI에서 편하다. 물론 API 키 자체를 secret manager에 두지 않으면 의미가 없다. 보통 self-host vault의 API 키를 GitHub Actions secret이나 1Password connect에 두는 식으로 분리한다(아이러니하게도 vault를 vault로 보호하는 구조가 된다).

Secrets Manager — 진짜 쓸 만한가

2023년에 베타로 시작한 Bitwarden Secrets Manager가 GA로 풀린 지 좀 됐다. HashiCorp Vault, Doppler, Infisical 같은 경쟁자들 사이에서 어떤 위치인지가 사실 더 흥미로운 지점이다.

어떤 워크로드에 어울리나

또한, 쓰면서 느낀 건, Secrets Manager는 "이미 Bitwarden을 쓰는 팀이 자연스럽게 확장"하는 데 가장 적합하다. HashiCorp Vault처럼 dynamic credential, transit encryption, PKI 같은 광범위한 영역을 다루지 않는다. 단순히 정적 secret을 프로젝트 단위로 나누고, 서비스 계정으로 접근 제어하고, CLI/SDK로 가져오는 흐름이다.

GitHub Actions에서 사용하는 패턴은 이렇다:

- name: Load secrets from Bitwarden
  uses: bitwarden/sm-action@v2
  with:
    access_token: ${{ secrets.BW_ACCESS_TOKEN }}
    base_url: https://vault.example.com
    secrets: |
      fc3b1c3a-0000-0000-0000-000000000001 > DATABASE_URL
      fc3b1c3a-0000-0000-0000-000000000002 > STRIPE_KEY

그러나, 이 액션이 환경변수로 secret을 주입한다. 워크플로우 로그에 값이 노출되지 않도록 masking은 자동이다. 자체 컨테이너에서 쓸 땐 bws CLI를 호출하면 된다:

# 5분마다 상태 확인하는 워커에서 사용
export BWS_ACCESS_TOKEN=...
bws secret get fc3b1c3a-0000-0000-0000-000000000001 --output json | jq -r .value

한계가 명확하다

dynamic secret이 없다. DB credential을 짧은 TTL로 발급해서 회전시키는 게 안 된다. 그게 필요한 조직은 HashiCorp Vault나 AWS Secrets Manager + Lambda 로테이션을 그대로 쓰면 된다. Bitwarden Secrets Manager는 그 자리를 넘보지 않는다.

그런데 역설적으로, 그 단순함이 강점이다. 작은 팀에서 HashiCorp Vault 클러스터를 운영하는 부담은 생각보다 크다. seal/unseal 흐름, Raft 스토리지 백업, 토큰 만료 디버깅. 직접 굴려본 경험으로는 운영 시간만 매주 2~3시간씩 깎아먹는다. 정적 secret만 잘 굴리면 되는 팀이라면 Bitwarden 쪽이 운영 비용이 훨씬 낮다.

패스키와 SSO — 마케팅 문구 vs 실제

패스키 지원 자체는 이미 2024년에 들어왔다. 단 2026년 들어 바뀐 건 "패스키 자체를 vault에 저장하고 다른 디바이스에서 동기화해서 쓰는" 흐름이 안정화됐다는 점이다. 데스크톱에서 패스키 만들고 모바일에서 쓰는 게 진짜로 된다.

패스키 동기화의 함정

거기에, 문제는 패스키를 어디에 저장할지 선택지가 너무 많아졌다는 거다. iCloud Keychain, Google Password Manager, Windows Hello, 그리고 Bitwarden. 각각이 패스키를 따로 만들고 따로 동기화한다. 한 사이트에 같은 계정으로 패스키가 3개 생기는 일이 흔하게 일어난다.

실제로 GitHub 계정에 iCloud 패스키 하나, Bitwarden 패스키 하나를 둔 상태에서 두 달 정도 굴려봤다. 결론은 "한 곳으로 통일하는 게 정신 건강에 좋다"는 거였다. 디바이스가 Mac/iPhone 위주면 iCloud, 다양한 OS를 오가면 Bitwarden을 기본으로 두고 OS 단의 패스키 저장을 끄는 게 낫다.

SSO 통합은 무료 플랜에선 의미 없다

한편, 여기는 마케팅 문구가 좀 과장된 영역이다. "Bitwarden은 SSO를 지원합니다"는 사실이지만, 의미 있는 SSO 흐름(SAML 2.0, OIDC for member provisioning)은 Enterprise 플랜 전용이다. 무료 플랜이나 Teams 플랜에서 기대하면 안 된다.

실제로, self-host로 Enterprise 기능 다 받는 무료 우회 같은 건 없다. 라이선스 키가 없으면 admin 콘솔에서 SSO 메뉴가 잠겨 있다. 작은 회사에서 무료로 다 굴리고 싶다면 Vaultwarden + Authelia/Authentik 조합이 더 현실적이다.

CLI와 SDK — AI 자동화 측면에서

그러나, 이 블로그가 AI 카테고리니까 자연스럽게 이어지는 얘기다. 요즘 Claude나 Cursor로 코드 작성할 때 secret 관리는 거의 필수 주제다.

MCP 관점에서의 Bitwarden

작성 시점 기준으로 공식 Bitwarden MCP 서버는 아직 없다(있다면 알려주길 바란다, 작성 시점에 검색해본 한도에서는 못 찾았다). 물론 bw CLI가 stdio로 깔끔하게 동작하기 때문에, 간단한 MCP wrapper를 만들어 Claude Desktop에 붙여본 적이 있다.

# Claude가 vault에서 read-only로 값을 읽도록 하는 최소 MCP 래퍼
import subprocess, json, os

def get_secret(name: str) -> str:
    """이름으로 vault 항목 검색, 첫 매치의 password 반환"""
    session = os.environ["BW_SESSION"]
    out = subprocess.check_output(
        ["bw", "list", "items", "--search", name, "--session", session]
    )
    items = json.loads(out)
    if not items:
        raise ValueError(f"no item matched: {name}")
    return items[0]["login"]["password"]

그래서, 이걸 MCP 서버로 노출하면 Claude가 "vault에서 staging DB 비밀번호 가져와서 마이그레이션 스크립트 만들어"같은 작업을 한 번에 할 수 있다. 위험한 흐름이라 read-only 권한과 명시적 화이트리스트는 필수다. 실수로 production credential을 LLM context에 흘리는 사고는 한 번이면 충분하다.

SDK의 의외의 가벼움

@bitwarden/sdk-napi 같은 Node 바인딩이 생기면서 CLI 없이도 vault 접근이 가능해졌다. 컨테이너 이미지에 node:slim + sdk만 넣으면 50MB 안쪽으로 정리된다. CLI 바이너리 통째로 넣는 것보다 가볍다.

단 위에서 말한 SDK 라이선스 변경이 여기 묻어 있다. 사내 도구 만들 땐 별 문제 없지만, 상용 제품에 임베드할 거라면 라이선스 검토 한 번은 해야 한다.

그래서 1Password 대신 Bitwarden인가

여기서 결론짓기는 어렵다. "1Password가 모두에게 답이다"라는 통념을 깨고 싶었던 거지, "Bitwarden이 모두에게 답이다"로 바꿔치기할 생각은 없다.

비교 항목 1Password (Business) Bitwarden (Teams/Enterprise)
UI/UX 완성도 높음 중간 (개선 중)
self-host 불가 공식 + Vaultwarden
SSO 모든 유료 플랜 Enterprise 전용
Secrets Manager 별도 제품(Connect/Service Accounts) 통합 제공
패스키 안정적 안정화 단계
가격 (사용자당/월, 2026-05 기준) 약 $7.99~ 약 $4~
오픈소스 일부 클라이언트 코드만 공개 본체 자유 라이선스

이처럼, 직접 운영 중인 환경에서 지금 굴리는 방식은 이렇다. 개인 vault는 Bitwarden self-host(Vaultwarden), 회사 공용 secret은 Bitwarden Secrets Manager, 그리고 dynamic DB credential이 필요한 일부는 여전히 HashiCorp Vault. 한 도구로 다 해결하려고 욕심내지 않는 게 운영 비용을 가장 많이 줄였다.

당장 실행할 만한 액션 세 가지를 적어둔다. 첫째, 본인 vault의 KDF 설정을 확인하라. PBKDF2가 박혀 있으면 마스터 패스워드 재설정 흐름에서 Argon2id로 옮길 수 있다. 둘째, GitHub Actions에서 plain secret을 쓰고 있다면 bitwarden/sm-action을 한 번 띄워보고 운영 부담을 가늠하라. 셋째, self-host 중이라면 Vaultwarden 릴리즈와 공식 클라이언트 메이저 버전의 호환 지연을 모니터링하는 cron 하나 정도는 박아두자. 한 사이클 묵혀서 업데이트하는 습관이 사고를 줄인다.

관련 글