
누구나 사용할 수 있는 로컬 비밀번호 관리자
<div align="center"> # APM **모두를 위한 더 나은 로컬 비밀번호 관리자.** [](https://golang.org) [](LICENSE) [](https://aaravmaloo.github.io/apm) [](https://github.com/aaravmaloo/apm/actions/workflows/ci.yml) [](https://github.com/aaravmaloo/apm/releases/latest) [](https://github.com/aaravmaloo/apm/stargazers) [](https://github.com/aaravmaloo/apm/issues) </div> APM은 Go와 Rust로 작성된 빠르고 제로 지식(zero-knowledge) CLI 비밀번호 관리자입니다. 비밀번호와 TOTP 코드부터 SSH 키, 의료 기록, 사진, 바이너리 파일에 이르기까지 **25개 이상의 구조화된 비밀 유형**을 단일 암호화된 볼트에 저장합니다. 이 저장소에서는 두 개의 바이너리가 제공됩니다. 개인용 `pm`과 공유 조직 볼트용 `pm-team`입니다. --- ### APM을 선택하는 이유 - **빠르고 배우기 쉬움** — 명령어나 플래그를 외울 필요가 없습니다. APM이 필요한 것을 물어봅니다. 최대 속도를 원하는 고급 사용자를 위한 CLI 플래그도 제공됩니다. - **제로 지식** — 마스터 비밀번호는 절대 저장되지 않습니다. Argon2id를 사용하여 세 개의 개별 32바이트 키가 파생됩니다. 본인 외에는 누구도 볼트를 복호화할 수 없습니다. - **이중 암호화** — AES-256-GCM 또는 XChaCha20-Poly1305 중에서 선택할 수 있습니다. AEAD 인증 위에 HMAC-SHA256을 통한 이중 계층 무결성을 제공합니다. - **휴대성** — 하나의 볼트 파일, 하나의 바이너리. 볼트를 어디든 가지고 다닐 수 있습니다. - **선택적 클라우드** — Google Drive, GitHub 또는 Dropbox에 동기화할 수 있습니다. 완전히 선택 사항이며, APM 사용에 계정이 필요하지 않습니다. - **AI 지원** — 범위가 지정된 토큰을 갖춘 네이티브 MCP 서버를 통해 Claude, Cursor 또는 모든 MCP 호환 에이전트가 볼트에 안전하게 접근할 수 있습니다. - **팀 지원** — `pm-team`에서 완전한 RBAC, 부서, 승인 워크플로 및 공유 볼트를 제공합니다. --- ### 빠른 시작 ```sh go build -o pm . pm setup # initialize vault and choose security profile pm unlock # start a session pm add # add a secret (interactive) pm get github # fuzzy search and retrieve pm lock # end session ``` **팀 에디션:** ```sh cd team go build -o pm-team . ``` ### 보안 유형 APM은 검증된 필드와 유형별 표시 로직을 갖춘 **25개의 구조화된 보안 유형**을 지원합니다: | # | 유형 | # | 유형 | |---|------|---|------| | 1 | 비밀번호 | 14 | Docker 레지스트리 | | 2 | TOTP | 15 | CI/CD 시크릿 | | 3 | 정부 발급 신분증 | 16 | 보안 메모 | | 4 | 의료 기록 | 17 | 복구 코드 | | 5 | 여행 정보 | 18 | 인증서 | | 6 | 연락처 | 19 | 은행 | | 7 | Wi-Fi | 20 | 문서 | | 8 | API 키 | 21 | 소프트웨어 라이선스 | | 9 | 토큰 | 22 | 법률 계약서 | | 10 | SSH 키 | 23 | 사진 | | 11 | SSH 구성 | 24 | 오디오 | | 12 | 클라우드 자격 증명 | 25 | 비디오 | | 13 | Kubernetes | | | --- ### 기능 **보안** - 제로 지식 Argon2id 키 유도 — 마스터 비밀번호는 절대 저장되지 않음 - 이중 AEAD 암호: AES-256-GCM 및 XChaCha20-Poly1305 - HMAC-SHA256 이중 계층 무결성 검사 - 네 가지 조정 가능한 보안 프로필: `standard`, `hardened`, `paranoid`, `legacy` - Watchtower (`pm watchtower`): 약한 비밀번호, 재사용된 비밀번호, 오래된 비밀번호, 유출된 비밀번호(옵트인, k-익명), 노출된 비밀번호, 만료 예정 항목, 누락된 2단계 인증 및 패스키, 위험한 키와 설정 검사를 포함한 0–100 보안 점수, 그리고 항목별 신뢰 점수와 활동 검토 - 잘못된 비밀번호는 점점 늘어나는 대기 시간을 추가함(영구 잠금은 없음), CLI, 앱, 확장 프로그램에서 공유됨 - 변조 감지 가능한 감사 로그가 볼트 외부에 저장됨 **볼트** - 단일 암호화 볼트 파일 — 모든 기기에서 휴대 가능 - 논리적 구획화를 위한 공간(폴더와 유사) - 대화형 브라우저와 키보드 탐색을 지원하는 퍼지 검색 - 메타데이터 검사기: 생성 날짜, 마지막 접근, 접근 횟수, 신뢰 점수 **TOTP** - 대화형 목록의 실시간 카운트다운 타이머 - 영구적인 사용자 지정 순서 - 직접 복사: `pm totp github` - 2FA 코드 자동 주입을 위한 자동 채우기 데몬 통합 **클라우드 동기화** - Google Drive(OAuth2 PKCE), GitHub(PAT), Dropbox(OAuth2 PKCE) - 종단 간 암호화 — 제공자는 평문을 절대 볼 수 없음 - 제공자별 항목 필터링을 위한 `.apmignore` - 충돌 해결: 덮어쓰기, 로컬 유지 또는 취소 - 백그라운드 자동 동기화 **세션** - 구성 가능한 만료 및 비활성 타임아웃을 갖춘 명시적 잠금 해제/잠금 - 자동화 및 AI 에이전트 접근을 위한 위임된 임시 세션 **MCP 서버** - 네이티브 Model Context Protocol 서버 - 범위 지정 권한 토큰: `read`, `secrets`, `write`, `admin` - 쓰기 작업은 데스크톱 앱에서 승인을 기다림; 어시스턴트는 자신의 변경 사항을 승인할 수 없음 - Claude Desktop, Cursor, Windsurf 및 모든 MCP 클라이언트와 호환 **복구** | 요소 | 명령 | |--------|---------| | 이메일 OTP | `pm auth email` | | 복구 키 | `pm auth recover` | | 쿼럼 공유(Shamir) | `pm auth quorum-setup` | | WebAuthn 패스키 | `pm auth passkey register` | | 일회용 복구 코드 | `pm auth codes generate` | **가져오기 / 내보내기** | 형식 | 가져오기 | 내보내기 | |--------|--------|--------| | JSON | `pm import json` | `pm export json` | | CSV | `pm import csv` | `pm export csv` | | TXT | `pm import txt` | `pm export txt` | **정책 엔진** ```yaml name: corporate-standard password_policy: min_length: 14 require_uppercase: true require_numbers: true require_symbols: true rotation_policy: rotate_every_days: 90 notify_before_days: 14 ``` ```sh pm policy load ./policies/ ``` **팀 에디션 (`pm-team`)** - 여러 역할을 지원하는 RBAC - 격리된 암호화 도메인을 갖춘 부서 - 민감한 항목에 대한 승인 워크플로 - 다중 사용자 자격 증명 공유를 위한 공유 보관함 --- ### 브라우저 확장 프로그램 APM 브라우저 확장 프로그램은 로그인 정보를 채워 넣고, 해당 사이트에 속한 일회용 코드를 제공하며, 새 로그인 정보를 저장하고, 패스키를 생성하고 사용합니다. 이 확장 프로그램은 마스터 비밀번호나 패스키의 개인 키를 절대 볼 수 없습니다. 확장 프로그램은 APM이 사용자의 컴퓨터에서 `127.0.0.1:41417`로 제공하는 작은 브리지와 통신합니다(다른 포트를 사용하려면 `APM_BRIDGE_PORT`를 설정하세요). **보관함에 접근하는 세 가지 방법** - 데스크톱 앱 사용 시: 앱이 열려 있는 동안 브리지가 실행됩니다. 페어링 요청과 브라우저 잠금 해제가 앱에 표시됩니다. - CLI만 사용, 연결 방식(권장): `pm extension link`를 한 번 실행하세요. 이 명령은 각 Chromium 브라우저(Chrome, Edge, Brave, Arc, Vivaldi, Chromium)에 `pm`을 네이티브 메시징 호스트로 등록하며, 이후에는 앱이 닫혀 있을 때마다 브라우저가 자체적으로 `pm`을 시작합니다. - CLI만 사용, 터미널에서 실행: `pm extension serve`를 실행하고 열어 두세요. 데스크톱 앱이 제공하는 것과 동일한 API를 제공하며, 잠금 해제, 잠금, 페어링 요청이 발생할 때마다 표시합니다. ```sh pm extension link # once per computer; confirm the code the extension shows pm extension serve # unlocks with your CLI session, or asks for the master password pm extension serve --locked # starts locked; unlock from the extension pm extension serve --idle 5m # locks after 5 minutes without browser activity (default 15m, 0 turns it off) ``` `pm extension serve`는 vault가 잠금 해제되거나 잠길 때 한 줄을 출력합니다. 중지하려면 Ctrl+C를 누르세요. vault 키는 메모리에서 삭제됩니다. 포트가 이미 사용 중이면 종료되며 APM 앱이 이미 확장 프로그램을 서비스하고 있을 수 있다고 알려줍니다. **브라우저 페어링** 1. 확장 프로그램에서 Connect를 선택합니다. 확장 프로그램이 6자리 코드를 표시합니다. 예: `K7M-2QX`. 2. APM이 동일한 코드를 표시하는지 확인합니다. 데스크톱 앱은 대화 상자를 열고, `pm extension link` 또는 `pm extension serve`는 터미널에서 예를 들어 `Connect Chrome on macOS? Code K7M-2QX [y/N]`와 같이 묻습니다. 3. 승인합니다. 확장 프로그램이 토큰을 받고 페어링됩니다. 요청은 2분 후에 만료되며, 한 번에 하나만 대기할 수 있습니다. `pm extension serve`는 터미널에서 실행 중이 아닐 때 자체적으로 요청을 거부합니다. 대신 수동으로 페어링하려면 `pm extension token --show`를 실행하고 토큰을 확장 프로그램의 수동 페어링 필드에 붙여넣으세요. **명령어** | 명령어 | 수행하는 작업 | |---------|--------------| | `pm extension link [--browser chrome,edge] [--no-wait]` | 데스크톱 앱이 닫혀 있을 때 브라우저가 확장 프로그램을 위해 `pm`을 시작하도록 허용 | | `pm extension unlink` | 브라우저가 `pm`을 시작하지 못하도록 중지. 페어링은 유지됨 | | `pm extension status [--port N]` | 어떤 브라우저가 연결되어 있는지, 현재 무엇이 확장 프로그램을 서비스하고 있는지, vault의 잠금 상태와 항목 수, 토큰 지문 표시 | | `pm extension serve [--port N] [--locked] [--idle 15m]` | Ctrl+C를 누를 때까지 이 터미널에서 확장 프로그램 서비스 | | `pm extension token [--show]` | 페어링 토큰 출력. `--show`가 없으면 마스킹됨 | | `pm extension rotate` | 페어링 토큰 교체. 페어링된 모든 브라우저는 다시 페어링해야 함. 실행 중인 브리지는 다음 요청 시 새 토큰을 사용 | | `pm totp link <entry> <domain>` | 일회용 코드를 사이트에 연결하여 확장 프로그램이 해당 사이트에서 제공하도록 함 | | `pm totp unlink <entry> [domain]` | 일회용 코드의 사이트 연결 제거 | `pm get`은 로그인에 있는 패스키와 연결된 일회용 코드를 표시하며, `pm totp`는 각 코드의 연결된 사이트를 표시합니다. **브리지가 비공개를 유지하는 방법** - `127.0.0.1`에서만 수신하며 `127.0.0.1` 또는 `localhost`로 주소 지정된 요청에만 응답하므로 DNS 리바인딩을 차단합니다. - `Origin`이 웹 페이지인 모든 요청을 거부합니다. `chrome-extension://`, `moz-extension://`, `safari-web-extension://` 오리진에만 CORS 헤더를 부여합니다. - 페어링을 제외한 모든 호출에는 페어링 토큰이 필요하며, APM 구성 디렉터리의 `bridge_token`에 저장되고 상수 시간으로 비교됩니다. - 목록 및 상세 호출에는 비밀 값이 절대 포함되지 않습니다. 확장 프로그램은 값을 표시하거나 채울 때 한 번에 하나의 필드만 요청하며, APM은 해당 접근을 기록합니다. - 패스키는 APM 내부에서 생성되고 서명됩니다. 확장 프로그램은 사이트의 오리진과 클라이언트 데이터의 해시를 보내고, APM은 서명하기 전에 해당 사이트가 해당 신뢰 당사자를 사용할 수 있는지 확인합니다. **로그인당 여러 웹사이트** 로그인은 기본 주소를 `website`에, 나머지 주소를 `urls`에 유지하며, 데스크톱 앱에서는 "Other websites"로 표시됩니다. 확장 프로그램은 이들 중 하나와 일치하는 페이지에서 로그인을 제공합니다. 기본적으로 일치는 동일한 등록 가능 도메인이므로 `accounts.google.com`과 `mail.google.com` 모두 `google.com`과 일치합니다. - 팝업에서 현재 있는 사이트를 로그인에 추가하고, 웹사이트를 추가하거나 제거하고, 둘 이상의 웹사이트로 새 로그인을 저장할 수 있습니다. - 저장되지 않은 사이트에서 로그인을 채우면 확장 프로그램이 먼저 묻습니다. "Fill and remember"를 선택하면 채우고 해당 사이트를 로그인에 추가합니다. - `pm totp link <entry> <domain>`은 일회용 코드에 대해 동일한 작업을 수행합니다. **웹사이트 로고** 데스크톱 앱과 확장 프로그램은 각 로그인의 첫 글자 대신 자체 로고를 표시합니다. APM은 로고를 사이트 자체에서 직접 가져오며, vault의 모든 사이트를 알게 될 제3자 파비콘 서비스에는 절대 요청하지 않습니다. - What: 로그인 첫 번째 웹사이트의 호스트(일회용 코드는 연결된 사이트를 사용), 소문자로 변환하고 `www.` 또는 포트 제거. `localhost`, IP 주소, `.local`, `.internal` 및 점이 없는 이름은 절대 가져오지 않음. - How: APM은 `https://<host>/`를 로드하고(최대 512 KiB), 페이지가 선언한 최적의 아이콘(`apple-touch-icon`, 그다음 가장 큰 PNG, 그다음 SVG)을 선택하며, `https://<host>/favicon.ico`로 폴백. HTTPS 전용, 최대 3회 리다이렉트, 사이트당 6초, 이미지 최대 256 KiB, 쿠키 없음. 루프백, 사설, 링크-로컬 또는 CGNAT 범위로 확인되는 주소는 거부됨. 요청은 시스템 프록시를 거치지 않고 사이트로 직접 전송됨. - When: 볼트가 잠금 해제되어 있고 데스크톱 앱 또는 `pm extension serve`가 실행 중일 때만, 한 번에 최대 4개 사이트. 실패한 사이트는 3일 후 재시도되고, 로고는 30일 후 새로고침됨. - Where: APM 설정 디렉터리의 `icons/`(macOS에서는 `~/Library/Application Support/apm/icons`, Linux에서는 `~/.config/apm/icons`, Windows에서는 `%AppData%\apm\icons`). 각 파일은 호스트의 SHA-256으로 이름이 지정되며, 최대 2000개까지 보관됨. 캐시는 암호화되지 않음: 이미지 옆의 각 `.json` 파일에 호스트 이름이 기록되므로, 설정 디렉터리를 읽을 수 있는 사람은 어떤 사이트에 로고가 있는지 볼 수 있음. - 사이트가 알게 되는 것: 귀하의 IP 주소와 APM이 해당 아이콘을 요청했다는 사실(사용자 에이전트는 `APM/<version> (+icon)`). 계정에 관한 정보는 없음. - 끄는 방법: 데스크톱 앱의 Settings, Appearance에서 "Show website icons"를 끄고(볼트 설정 `siteIcons`이며 `pm extension serve`도 이를 준수함), "Clear icon cache"를 선택하여 캐시를 삭제. `APM_ICONS_OFFLINE=1`을 설정하면 프로세스에서 모든 가져오기를 중지함(예: 테스트 또는 CI에서). 캐시된 로고는 지우기 전까지 계속 표시됨. --- ### 보안 프로필 | 프로필 | Argon2 메모리 | 반복 횟수 | 병렬성 | 사용 사례 | |---------|--------------|------------|-------------|----------| | `standard` | 64 MB | 3 | 2 | 대부분의 머신 | | `hardened` | 256 MB | 5 | 4 | 워크스테이션 (≥8 GB RAM) | | `paranoid` | 512 MB | 6 | 4 | 서버 (≥16 GB RAM) | | `legacy` | PBKDF2 | 600,000 | 1 | 하위 호환성 | APM은 `pm setup` 중에 CPU 코어와 RAM을 자동 감지하여 최적의 프로필을 추천함. ### 개발 현황 및 이력 (이 글은 소유자가 작성한 것입니다) 2026년 3월 30일 기준, 저는 현재 APM의 GUI 작업을 진행하고 있습니다. 처음에는 CLI 애플리케이션으로 시작했습니다. 이슈 #38에 모든 내용이 자세히 설명되어 있습니다. 전반적으로 저는 APM이 더욱 많은 사용자층에 도달하기를 원합니다. GUI는 apm-gui 저장소에 별도로 유지하거나 조직을 만들어 두 저장소를 모두 그곳으로 옮길 예정입니다. 저는 APM을 진정한 개인 프로젝트로 시작했습니다. 어느 날 저녁, 제 자신만의 비밀번호 관리자를 만들고 싶었을 때 시작되었습니다. 저는 TOTP에 zoho password를 사용하고 있었는데 지겨웠습니다. 작동하기까지 믿을 수 없을 만큼 느렸고, 토큰에 평문 파일을 사용하고 있었는데 이는 안전하지 않습니다. 현재로서는 프로젝트를 포기하거나 은퇴시킬 계획이 없습니다. 오랫동안 기능을 유지할 것입니다. 매일 더 나아지도록 노력하고 매일 사용합니다. 때때로 저장소가 비활성 상태일 수 있는데, 그때는 애플리케이션을 테스트하고 실험하는 시기입니다. --- ### 릴리스 구조 | 계층 | 안정적? | 볼트 안전? | 목적 | |------|---------|-------------|---------| | Canary | ❌ | ❌ | 가장 빠른 기능 미리보기 — 볼트를 손상시킬 수 있음 | | Alpha | ❌ | ✅ | 불안정한 기능, 볼트 무결성 유지됨 | | Beta | ✅ | ✅ | 완전히 테스트된 기능, 신중한 롤아웃 | | Stable | ✅ | ✅ | 프로덕션 준비 완료 릴리스 | > Canary 릴리스를 시도하기 전에 항상 볼트를 백업하세요. P.S. 일부 릴리스의 경우, 불필요하게 많은 계층을 만들지 않고 얼마나 빠르고 쉽게 출시할 수 있는지에 따라 일부 계층이 릴리스되지 않을 수 있습니다. --- # AI 사용 APM을 개발하고 전체 제품군을 유지 관리하는 것은 한 번에 모두 해내기 쉽지 않습니다. 따라서 우리는 **25%** 의 AI 생성 코드(주로 UI 변경과 중요하지 않으며 암호화와 무관한 변경)를 사용합니다. 그러나 APM에서는 AI 사용에 관한 몇 가지 정책을 두고 있으며, 아래에 나열합니다. - AI는 소규모 기능과 vault를 건드리지 않는 기능을 개발하는 데에만 사용됩니다 - AI 편집은 신중하게 다루고 꼼꼼히 검토해야 합니다 - AI 편집은 철저히 테스트해야 합니다 이러한 정책은 우리가 AI를 책임감 있게 사용하고 모두를 위해 APM을 더 나은 것으로 만들도록 보장합니다! ### 문서 전체 문서는 **[aaravmaloo.github.io/apm](https://aaravmaloo.github.io/apm)** 에서 확인할 수 있습니다 - [설치](https://aaravmaloo.github.io/apm/getting-started/installation/) - [첫 단계](https://aaravmaloo.github.io/apm/getting-started/first-steps/) - [CLI 레퍼런스](https://aaravmaloo.github.io/apm/reference/cli/) - [아키텍처](https://aaravmaloo.github.io/apm/concepts/architecture/) - [암호화](https://aaravmaloo.github.io/apm/concepts/encryption/) - [팀 에디션](https://aaravmaloo.github.io/apm/guides/team-edition/) - [MCP 통합](https://aaravmaloo.github.io/apm/guides/mcp-integration/) - [기여하기](https://aaravmaloo.github.io/apm/contributing/) --- ### 기여하기 기여를 환영합니다. 가이드라인은 [CONTRIBUTING.md](https://aaravmaloo.github.io/apm/contributing/)를 참조하세요. --- ### 라이선스 [GPL-3.0 License](https://github.com/aaravmaloo/apm/blob/master/LICENSE) © Aarav Maloo