
네이티브 OS 자격 증명 저장소(macOS 키체인, Linux Secret Service, Windows Credential Manager)를 사용하여 환경 비밀을 관리하는 안전한 CLI 도구
네이티브 OS 자격 증명 저장소를 사용하는 안전한 환경 변수 비밀 관리 도구.

myapp.dev, stripe-api.prod, work.staging)cmd로 명령 저장 및 재실행 (검색, 목록, 실행, 삭제).env 파일로 비밀 내보내기 (audit를 통한 생성 추적 포함)eval $(envsec env)).env 파일에서 비밀 로드 (충돌 감지 포함)envsec tui)다음 패키지를 포함하는 모노레포입니다:
Node.js 또는 Bun에서 비밀에 프로그래밍 방식으로 접근하려면 @envsec/sdk를 사용하세요:```bash
npm install @envsec/sdk
I need the actual content of chunk 3 to translate it. Please provide the Markdown text you'd like translated.```typescript
import { loadSecrets } from "@envsec/sdk";
// Load and inject into process.env
await loadSecrets({ context: "myapp.dev", inject: true });
// Or use the client for full control
import { EnvsecClient } from "@envsec/sdk";
const client = await EnvsecClient.create({ context: "myapp.dev" });
const apiKey = await client.get("api.key");
await client.close();
전체 API, 다중 컨텍스트 지원 및 옵션에 대한 자세한 내용은 SDK 문서를 참조하세요.
추가 종속성 없음. security CLI 도구를 통해 내장된 Keychain을 사용합니다.
libsecret-tools( secret-tool 명령 제공)가 필요하며, 이는 D-Bus를 통해 GNOME Keyring, KDE Wallet 또는 기타 Secret Service API 제공자와 통신합니다.```bash
sudo apt install libsecret-tools
sudo dnf install libsecret
sudo pacman -S libsecret
D-Bus 세션이 실행 중이고 키링 데몬(예: `gnome-keyring-daemon`)이 활성화되어 있어야 합니다. 대부분의 데스크톱 환경에서는 이를 자동으로 처리합니다.
### Windows
추가 종속성이 필요 없습니다. `cmdkey`와 PowerShell을 통해 내장된 Windows 자격 증명 관리자를 사용합니다.
## 설치
### Homebrew (macOS / Linux)```bash
brew tap davidnussio/homebrew-tap
brew install envsec
npm install -g envsec
### npx (설치 없이)```bash
npx envsec
mise use -g npm:envsec
## 사용법
대부분의 명령은 `--context`(또는 `-c`)로 컨텍스트를 지정해야 합니다.
컨텍스트는 비밀을 그룹화하기 위한 자유 형식 레이블입니다. 예: `myapp.dev`, `stripe-api.prod`, `work.staging`.
### 전역 옵션
다음 옵션은 모든 명령에서 사용할 수 있습니다:
- `--context`, `-c` — 컨텍스트 이름(예: `myapp.dev`, `stripe-api.prod`). `ENVSEC_CONTEXT` 환경 변수도 읽습니다
- `--debug`, `-d` — 디버그 로깅 활성화
- `--json` — 스크립팅을 위해 JSON 형식으로 출력
- `--db` — SQLite 데이터베이스 파일 경로(기본값: `~/.envsec/store.sqlite`). `ENVSEC_DB` 환경 변수도 읽습니다
### 사용자 지정 데이터베이스 경로
기본적으로 메타데이터는 `~/.envsec/store.sqlite`에 저장됩니다. `--db` 또는 `ENVSEC_DB` 환경 변수로 이를 재정의할 수 있습니다:```bash
# Use a project-local database
envsec --db ./local-store.sqlite -c myapp.dev list
# Or via environment variable
export ENVSEC_DB=/shared/team/envsec.sqlite
envsec -c myapp.dev list
--db 플래그는 ENVSEC_DB보다 우선합니다. 사용 사례로는 프로젝트별 데이터베이스, 네트워크 드라이브의 팀 공유 데이터베이스, 임시 스토리지를 사용하는 CI/CD 등이 있습니다.
OS 자격 증명 저장소에 비밀을 저장합니다.
<key> — 비밀 키 이름 (예: api.key, db.password)--value, -v — 저장할 값 (대화형 마스킹 프롬프트를 위해 생략 가능)--expires, -e — 만료 기간 (예: 30m, 2h, 7d, 4w, 3mo, 1y)```bashenvsec -c myapp.dev add api.key --value "sk-abc123"
envsec -c myapp.dev add api.key -v "sk-abc123"
envsec -c myapp.dev add api.key
envsec -c myapp.dev add api.key -v "sk-abc123" --expires 30d
envsec -c myapp.dev add api.key -v "sk-abc123" -e 6mo
### Get a secret
OS 자격 증명 저장소에서 비밀 값을 검색합니다.
- `<key>` — 검색할 비밀 키 이름
- `--quiet`, `-q` — 원시 값만 출력합니다(경고나 추가 출력 없음)
- `--json` — JSON 형식으로 출력합니다(context, key, value, expires_at 포함)```bash
envsec -c myapp.dev get api.key
# Print only the raw value (no warnings or extra output)
envsec -c myapp.dev get api.key --quiet
envsec -c myapp.dev get api.key -q
OS 자격 증명 저장소에서 비밀을 제거합니다.
<key> — 삭제할 비밀 키 이름(--all 사용 시 선택 사항)--yes, -y — 확인 프롬프트 건너뛰기--all — 컨텍스트의 모든 비밀 삭제```bash
envsec -c myapp.dev delete api.keyenvsec -c myapp.dev del api.key
### 비밀번호 이름 변경
동일한 컨텍스트 내에서 비밀번호 키의 이름을 변경합니다. 값과 만료 메타데이터는 유지됩니다.
- `<old-key>` — 현재 비밀번호 키 이름
- `<new-key>` — 새 비밀번호 키 이름
- `--force`, `-f` — 대상이 이미 존재하는 경우 덮어씁니다```bash
# Rename a key
envsec -c myapp.dev rename old.key new.key
# Overwrite target if it already exists
envsec -c myapp.dev rename old.key existing.key --force
컨텍스트의 모든 시크릿 키와 메타데이터를 나열합니다.
--json — JSON 형식으로 출력```bash
envsec -c myapp.dev list### 모든 컨텍스트 나열
비밀번호 개수와 함께 사용 가능한 모든 컨텍스트를 나열합니다.
- `--json` — JSON 형식으로 출력```bash
# Without --context, lists all available contexts with secret counts
envsec list
글로브 패턴을 사용하여 시크릿 또는 컨텍스트를 검색합니다.
<pattern> — 검색할 글로브 패턴 (예: api.*, myapp.*)--json — JSON 형식으로 출력```bashenvsec -c myapp.dev search "api.*"
envsec search "myapp.*"
### 컨텍스트 간 시크릿 이동
한 컨텍스트에서 다른 컨텍스트로 시크릿을 이동합니다. 이동 후 원본 시크릿은 제거됩니다.
- `<pattern>` — 이동할 Glob 패턴 또는 정확한 키 (`--all` 사용 시 선택 사항)
- `--to`, `-t` — 시크릿을 이동할 대상 컨텍스트
- `--all` — 소스 컨텍스트의 모든 시크릿 이동
- `--force`, `-f` — 대상 컨텍스트의 기존 시크릿 덮어쓰기
- `--yes`, `-y` — 확인 프롬프트 건너뛰기```bash
# Move a single secret
envsec -c myapp.dev move api.token --to myapp.prod
# Move secrets matching a glob pattern
envsec -c myapp.dev move "redis.*" --to myapp.prod -y
# Move all secrets from one context to another
envsec -c myapp.dev move --all --to myapp.prod -y
# Overwrite existing secrets in the target context
envsec -c myapp.dev move "redis.*" --to myapp.prod --force -y
한 컨텍스트에서 다른 컨텍스트로 비밀을 복사합니다. 원본 비밀은 그대로 유지됩니다.
<pattern> — 복사할 키의 Glob 패턴 또는 정확한 키 (--all 사용 시 선택 사항)--to, -t — 비밀을 복사할 대상 컨텍스트--all — 소스 컨텍스트의 모든 비밀 복사--force, -f — 대상 컨텍스트의 기존 비밀 덮어쓰기--yes, -y — 확인 프롬프트 건너뛰기```bashenvsec -c myapp.dev copy api.token --to myapp.staging
envsec -c myapp.dev copy "redis.*" --to myapp.staging -y
envsec -c myapp.dev copy --all --to myapp.staging -y
envsec -c myapp.dev copy "redis.*" --to myapp.staging --force -y
### 비밀 값으로 명령 실행
비밀 값을 플레이스홀더로 보간하거나 환경 변수로 주입하여 명령을 실행합니다.
- `<command>` — 실행할 명령. 비밀 값 보간에는 `{key}` 플레이스홀더를 사용합니다
- `--inject`, `-i` — 모든 컨텍스트 비밀 값을 환경 변수로 주입합니다 (`KEY.NAME` → `KEY_NAME`)
- `--save`, `-s` — 이 명령을 나중에 사용할 수 있도록 저장합니다
- `--name`, `-n` — 저장된 명령의 이름 (`--save`와 함께 사용 시 생략하면 대화형으로 입력받습니다)```bash
# Placeholders {key} are resolved with secret values before execution
envsec -c myapp.dev run 'curl {api.url} -H "Authorization: Bearer {api.token}"'
# Any {dotted.key} in the command string is replaced with its value
envsec -c myapp.prod run 'psql {db.connection_string}'
# Inject ALL context secrets as environment variables (KEY.NAME → KEY_NAME)
envsec -c myapp.dev run --inject 'node server.js'
envsec -c myapp.dev run -i 'docker compose up'
# Combine --inject with placeholders
envsec -c myapp.dev run --inject 'curl {api.url} -H "Authorization: Bearer $API_TOKEN"'
# Save the command for later use with --save (-s) and --name (-n)
envsec -c myapp.dev run --save --name deploy 'kubectl apply -f - <<< {k8s.manifest}'
# If you use --save without --name, you'll be prompted interactively
envsec -c myapp.dev run --save 'psql {db.connection_string}'
만약 어떤 플레이스홀더가 존재하지 않는 비밀을 참조하면, 명령이 실행되지 않고 명확한 오류가 표시됩니다:``` ❌ Missing secrets in context "myapp.dev":
Add them with: envsec -c myapp.dev add
### 저장된 명령어
저장된 명령어는 `cmd` 하위 명령어 아래에 있으며, 비밀 작업과 분리되어 유지됩니다.
#### cmd list
저장된 모든 명령어를 나열합니다.```bash
envsec cmd list
저장된 명령을 실행합니다(저장 당시의 컨텍스트를 사용).
<name> — 실행할 저장된 명령의 이름--override-context, -o — 실행 시 저장된 컨텍스트를 재정의합니다--quiet, -q — 정보성 출력을 억제합니다(명령 출력만 표시)--inject, -i — 모든 컨텍스트 시크릿을 환경 변수로 주입합니다```bash
envsec cmd run deployenvsec cmd run deploy --quiet envsec cmd run deploy -q
envsec cmd run deploy --override-context myapp.prod envsec cmd run deploy -o myapp.prod
envsec cmd run deploy --inject envsec cmd run deploy -i
#### cmd search
저장된 명령어를 이름 또는 명령 문자열로 검색합니다.
- `<pattern>` — 검색 패턴
- `--name`, `-n` — 명령 이름에서만 검색
- `--command`, `-m` — 명령 문자열에서만 검색```bash
envsec cmd search psql
# Search only by name
envsec cmd search deploy -n
# Search only by command string
envsec cmd search kubectl -m
저장된 명령을 삭제합니다.
<name> — 삭제할 명령의 이름```bash
envsec cmd delete deploy### .env 파일 생성
컨텍스트의 모든 비밀을 `.env` 파일로 내보냅니다.
- `--output`, `-o` — 출력 파일 경로 (기본값: `.env`)```bash
# Creates .env with all secrets from the context
envsec -c myapp.dev env-file
# Specify a custom output path
envsec -c myapp.dev env-file --output .env.local
키는 UPPER_SNAKE_CASE로 변환됩니다 (예: api.token → API_TOKEN).
eval 또는 셸 소싱과 함께 사용할 export 문을 출력합니다.
--shell, -s — 대상 셸 구문: bash (기본값), zsh, fish, powershell--unset, -u — export 대신 unset/제거 명령을 출력합니다.```basheval $(envsec -c myapp.dev env)
envsec -c myapp.dev env --shell fish envsec -c myapp.dev env --shell powershell
eval $(envsec -c myapp.dev env --unset)
envsec -c myapp.dev env --unset --shell fish
지원되는 셸: `bash`(기본값), `zsh`, `fish`, `powershell`. 키는 `UPPER_SNAKE_CASE`로 변환됩니다(예: `api.token` → `API_TOKEN`). 출력은 stdout으로 전달되므로 `eval`에 파이프하거나 직접 소싱할 수 있습니다 — 디스크에 파일이 기록되지 않습니다.
### 비밀번호 범위 셸 세션 시작
컨텍스트의 모든 비밀번호가 환경 변수로 주입된 대화형 하위 셸을 실행합니다. `exit`하면 비밀번호가 사라집니다 — 정리 작업이 필요 없습니다.
- `--shell`, `-s` — 실행할 셸(`bash`, `zsh`, `fish`, `powershell`). 기본값: 자동 감지
- `--no-inherit` — 부모 환경 변수를 상속하지 않음
- `--quiet`, `-q` — 시작/종료 배너 표시 안 함```bash
envsec -c myapp.dev shell
Please provide the Markdown content to translate.``` ▶ envsec shell — context: myapp.dev (8 secrets loaded) Type 'exit' or press Ctrl+D to leave the session.
(envsec:myapp.dev) ~ $ echo $DATABASE_URL postgres://user:pass@localhost/mydb
(envsec:myapp.dev) ~ $ exit → Exiting envsec shell — secrets cleared.
I need the actual content of chunk 55 to translate it. Please provide the Markdown text you'd like translated.```bash
# Force a specific shell
envsec -c myapp.dev shell --shell zsh
# Only envsec secrets in env (no parent variables, except PATH)
envsec -c myapp.dev shell --no-inherit
# Suppress the startup/exit banner
envsec -c myapp.dev shell --quiet
ENVSEC_CONTEXT 변수는 세션 내에서 항상 설정되므로, 스크립트나 프롬프트 사용자 지정에서 이를 참조할 수 있습니다.
.env 파일에서 컨텍스트로 시크릿을 가져옵니다.
--input, -i — 입력 .env 파일 경로 (기본값: .env)--force, -f — 확인 메시지 없이 기존 시크릿 덮어쓰기--batch, -b — 배치 모드: 모든 시크릿이 가져올 때까지 데이터베이스 저장 지연```bashenvsec -c myapp.dev load
envsec -c myapp.dev load --input .env.local
envsec -c myapp.dev load --force
키는 `UPPER_SNAKE_CASE`에서 `dotted.lowercase`로 변환됩니다 (예: `API_TOKEN` → `api.token`). 키가 이미 존재하면 `--force` (`-f`)가 제공되지 않는 한 경고와 함께 건너뜁니다.
### 비밀 공유 (GPG 암호화)
GPG를 사용하여 컨텍스트의 모든 비밀을 팀 구성원을 위해 암호화합니다.
- `--encrypt-to` — 암호화 대상 GPG 수신자 키 (이메일, 키 ID 또는 지문)
- `--output`, `-o` — 출력 파일 경로 (기본값: stdout). 명시적으로 stdout을 사용하려면 `-` 사용
- `--json` — 암호화된 페이로드 내부에 JSON 형식 사용 (기본값: `.env` 형식)```bash
# Encrypt all secrets from a context for a team member
envsec -c myapp.dev share --encrypt-to [email protected]
# Save encrypted output to a file
envsec -c myapp.dev share --encrypt-to [email protected] -o secrets.enc
# Use JSON format inside the encrypted payload
envsec -c myapp.dev --json share --encrypt-to [email protected] -o secrets.enc
수신자는 gpg --decrypt secrets.enc로 복호화한 뒤 그 결과를 envsec load로 파이프할 수 있습니다. 기본적으로 암호화된 페이로드는 .env 형식(KEY="value")을 사용하며, --json을 사용하면 구조화된 JSON 객체를 사용합니다. GPG가 설치되어 있어야 하며 수신자의 공개 키가 키링에 있어야 합니다.
만료되었거나 곧 만료될 비밀과 추적 중인 .env 파일 내보내기를 확인합니다.
--within, -w — 이 기간 내에 만료되는 비밀을 표시합니다 (기본값: 30d). 이미 만료된 항목만 표시하려면 0d를 사용하세요--json — JSON 형식으로 출력합니다```bashenvsec -c myapp.dev audit
envsec -c myapp.dev audit --within 7d
envsec -c myapp.dev audit --within 0d
envsec audit
envsec -c myapp.dev audit --json
`envsec add`를 통해 `--expires` 기간이 설정된 시크릿은 메타데이터에 추적됩니다. `audit` 명령은 이미 만료되었거나 지정된 기간 내에 만료될 시크릿을 검사합니다. `get` 및 `list` 명령도 만료 경고를 인라인으로 표시합니다.
`audit` 명령은 생성된 `.env` 파일도 추적합니다. `env-file`이 사용될 때마다 출력 경로, 컨텍스트, 타임스탬프가 기록됩니다. 감사 출력에는 이러한 파일을 나열하는 두 번째 섹션이 포함됩니다. 추적된 `.env` 파일이 디스크에 더 이상 존재하지 않으면, audit는 자동으로 이를 메타데이터에서 제거하고 정리 사실을 보고합니다.
### 임의 시크릿 생성
암호학적으로 안전한 임의 시크릿을 생성하며, 선택적으로 저장할 수 있습니다.
- `<key>` — 시크릿 키 이름 (선택 사항; 독립형 비밀번호 생성 시 생략)
- `--length`, `-l` — 생성된 시크릿의 길이 (기본값: `32`)
- `--prefix`, `-p` — 생성된 시크릿 앞에 붙일 접두사 (예: `sk_`)
- `--expires`, `-e` — 만료 기간 (예: `30m`, `2h`, `7d`, `4w`, `3mo`, `1y`)
- `--alphanumeric`, `-a` — 영숫자 문자만 사용 `[a-zA-Z0-9]` (기본값)
- `--special`, `-s` — 일반적인 특수 문자 포함 `[a-zA-Z0-9!@#$%^&*]`
- `--all-chars`, `-A` — 최대 엔트로피를 위해 모든 인쇄 가능한 ASCII 문자 사용```bash
# Generate and store a 32-char alphanumeric secret
envsec -c myapp.dev secret api.key
# Custom length and prefix
envsec -c myapp.dev secret api.key --prefix "sk_" --length 48
# Character sets:
# --alphanumeric (-a) [a-zA-Z0-9] (default)
# --special (-s) [a-zA-Z0-9] + !@#$%^&*
# --all-chars (-A) all printable ASCII
envsec -c myapp.dev secret db.password --special --length 64
# With expiry
envsec -c myapp.dev secret api.key --prefix "sk_" -l 48 --expires 90d
# Standalone password generator (no store, just print)
envsec secret --length 32
envsec secret --special --length 64 --prefix "pk_"
컨텍스트와 키가 모두 제공되면 생성된 값이 저장되고 출력됩니다. 둘 중 하나라도 없으면 원시 값이 stdout으로 출력됩니다. 이는 pbcopy, xclip 또는 다른 도구로 파이프할 때 유용합니다.
envsec에는 비밀을 대화형으로 관리하기 위한 전체 화면 터미널 UI가 포함되어 있습니다. 명령어를 외울 필요가 없습니다.```bash
envsec tui
envsec -c myapp.dev tui
TUI는 메인 메뉴에서 접근할 수 있는 8개의 화면을 제공합니다:
- **Contexts** — 모든 컨텍스트 탐색, `s`로 활성 컨텍스트 설정, `x`로 컨텍스트 지우기, 시크릿 개수 확인, 전체 컨텍스트 삭제
- **Secrets** — 테이블에서 시크릿 목록 표시, 값 공개, 시크릿 추가 또는 삭제
- **Add Secret** — 마스킹된 입력과 선택적 만료 기간이 있는 대화형 양식
- **Search** — 시크릿 또는 컨텍스트 전체에서 glob 패턴 검색
- **Saved Commands** — 저장된 명령 템플릿 목록, 보기, 삭제
- **Audit** — 만료되었거나 곧 만료될 시크릿 확인, 추적된 `.env` 파일 내보내기 검토
- **Import .env** — `.env` 파일에서 현재 컨텍스트로 시크릿 로드
- **Export .env** — 시크릿을 `.env` 파일로 내보내기(감사용으로 추적됨)
키보드 단축키:
| 키 | 동작 |
|-----|--------|
| `↑` / `↓` | 메뉴 항목 및 테이블 행 탐색 |
| `Enter` | 선택 / 확인 |
| `c` | 컨텍스트 보기 열기(메인 메뉴) |
| `s` | 선택 항목을 활성 컨텍스트로 설정(컨텍스트 보기) |
| `x` | 활성 컨텍스트 지우기(컨텍스트 보기) |
| `a` | 새 시크릿 추가(시크릿 보기) |
| `d` | 선택한 항목 삭제 |
| `r` | 시크릿 값 공개(상세 보기) |
| `Esc` | 뒤로 가기 / 취소 |
| `q` | TUI 종료 |
### 설정 진단
envsec 설치를 확인하려면 상태 점검을 실행하세요.
- `--json` — 스크립팅을 위해 JSON 형식으로 출력```bash
# Run all health checks
envsec doctor
# JSON output for scripting
envsec --json doctor
doctor 명령은 envsec 설치가 올바르게 작동하는지 확인합니다. 다음 항목을 검사합니다:
ENVSEC_DB, ENVSEC_CONTEXT)envsec는 bash, zsh, fish에 대한 동적 탭 완성을 지원합니다. 자동 완성은 컨텍스트를 인식합니다. 즉, 메타데이터 데이터베이스를 쿼리하여 실제 컨텍스트 이름, 비밀 키 및 저장된 명령 이름을 실시간으로 제안합니다.```bash
eval "$(envsec --completions bash)"
eval "$(envsec --completions zsh)"
envsec --completions fish | source
동적으로 완성되는 항목:
- `--context` / `-c` — 모든 컨텍스트 목록 표시
- 비밀 키 인자(`get`, `add`, `delete`) — 현재 컨텍스트의 키 목록 표시
- `cmd run` / `cmd delete` — 저장된 명령 이름 목록 표시
- `--override-context` / `-o` — `cmd run`의 컨텍스트 목록 표시
- 하위 명령, 플래그, 정적 선택 항목(셸 등)도 완성됨
## 비교
envsec은 환경 비밀을 관리하는 다른 도구와 어떻게 비교되나요?
| 기능 | envsec | dotenv / dotenvx | 1Password CLI (`op`) |
|---|---|---|---|
| 비밀 저장소 | OS 자격 증명 저장소(Keychain, Secret Service, Credential Manager) | 디스크의 `.env` 파일(dotenvx는 암호화 추가) | 1Password 클라우드 볼트 |
| 저장 시 암호화 | OS에 위임(Keychain, GNOME Keyring, DPAPI) | 없음(dotenv) / 파일별 ECIES(dotenvx) | 1Password 클라우드의 AES-256 |
| 디스크의 비밀 | 절대 없음 — 값은 OS 자격 증명 저장소로 직접 이동 | 항상 — `.env` 파일은 기본적으로 평문 | 로컬에 없음(런타임에 클라우드에서 가져옴) |
| 오프라인 접근 | 전체 — 비밀은 OS 저장소에 로컬로 존재 | 전체 — 파일은 로컬에 존재 | 네트워크 필요(앱에서 오프라인 캐시 항목 사용 가능) |
| 계정 / 구독 | 없음 — 무료, 오픈 소스, 가입 불필요 | 무료(dotenv) / 무료 오픈 소스(dotenvx) | 유료 구독(개인 약 $3/월, 비즈니스 사용자당 약 $8/월) |
| 크로스 플랫폼 | macOS, Linux, Windows | Node.js가 있는 모든 플랫폼 / 모든 런타임(dotenvx) | macOS, Linux, Windows |
| 컨텍스트 / 환경 구성 | 컨텍스트(예: `myapp.dev`, `stripe.prod`) | 환경별 별도 `.env` 파일 | 볼트 및 항목 |
| 비밀로 명령 실행 | `envsec run` — 플레이스홀더 보간 + `--inject` 환경 변수 | `dotenvx run -- cmd` — 암호화된 `.env`에서 주입 | `op run -- cmd` — 비밀 참조를 통해 주입 |
| `.env` 파일로 내보내기 | `envsec env-file`(감사용으로 추적) | 기본 형식 — `.env` 파일이 진실의 원천 | `op inject --out-file` |
| `.env` 파일에서 가져오기 | `envsec load`(충돌 감지 포함) | 해당 없음 — `.env`가 기본 저장소 | 수동 항목 생성 |
| 셸 환경 내보내기 | `eval $(envsec env)` — bash, zsh, fish, powershell | `dotenvx run` 또는 `node -r dotenv/config` | `op run --env-file` |
| 대화형 셸 세션 | `envsec shell` — 자동 정리 기능이 있는 범위 지정 하위 셸 | 기본 제공 아님 | 기본 제공 아님 |
| 비밀 검색 | 키 및 컨텍스트의 글로브 패턴 | 기본 제공 아님 | `op item list --tags/--category` 필터링 |
| 만료 / 회전 감사 | `envsec audit` — 만료됨, 곧 만료됨, 추적된 `.env` 파일 | 기본 제공 아님 | Watchtower(앱 내, CLI 아님) |
| 저장된 명령 | `envsec cmd` — 저장, 목록, 검색, 실행, 삭제 | 기본 제공 아님 | 기본 제공 아님 |
| 비밀 이동 / 복사 | 컨텍스트 간 `envsec move` 및 `envsec copy` | 수동 파일 복사 | 볼트 간 `op item move` |
| 비밀 이름 변경 | `envsec rename`(값 및 메타데이터 보존) | `.env` 파일 수동 편집 | `op item edit` |
| GPG 암호화 공유 | `envsec share --encrypt-to` | git에 커밋된 암호화된 `.env` 파일(dotenvx) | 기본 제공 볼트 공유, 팀 프로비저닝 |
| 대화형 TUI | `envsec tui` — 전체 화면 터미널 UI | 기본 제공 아님 | 기본 제공 아님 |
| 상태 진단 | `envsec doctor` — 플랫폼, 키체인, DB 무결성 확인 | 기본 제공 아님 | 기본 제공 아님 |
| 셸 완성 | bash, zsh, fish용 동적(컨텍스트, 키, 명령) | 기본 제공 아님 | bash, zsh, fish, powershell용 정적 완성 |
| SDK / 프로그래밍 접근 | Node.js / Bun용 `@envsec/sdk` | `require('dotenv').config()` — 핵심 사용 사례 | 1Password SDK(Node.js, Python, Go 등) |
| 팀 / 다중 사용자 | GPG 공유(수동) | 암호화된 `.env`를 사용한 Git 기반 공유(dotenvx) | 기본 제공 팀 관리, RBAC, 감사 로그 |
<!-- | CI/CD 통합 | 표준 CLI — Node.js가 실행되는 모든 곳에서 작동 | 모든 CI 파이프라인에서 `dotenvx run` | 서비스 계정, 기본 CI/CD 통합 | -->
| 생체 인증 | OS 생체 인식 상속(예: macOS Keychain 잠금 해제) | 없음 | 앱 통합을 통한 지문 / Touch ID |
| 메타데이터 추적 | SQLite(키 이름, 타임스탬프 — 값은 절대 아님) | 없음 | 클라우드 기반 항목 기록 및 감사 로그 |
요약하자면: dotenv는 가장 간단한 접근 방식(디스크의 파일)이고, 1Password CLI는 클라우드 동기화와 RBAC를 갖춘 팀에게 가장 기능이 풍부하며, envsec은 그 사이에 위치합니다 — 계정 없이, 클라우드 의존성 없이 OS 네이티브 암호화를 제공하고, `.env` 파일이 할 수 있는 것 이상을 제공하는 개발자 중심 워크플로우를 제공합니다.
## 작동 방식
비밀은 네이티브 OS 자격 증명 저장소에 저장됩니다. 백엔드는 플랫폼에 따라 자동으로 선택됩니다:
| OS | 백엔드 | 도구 / API |
|---------|--------------------------------|-------------------------------------|
| macOS | Keychain | `security` CLI |
| Linux | Secret Service API (D-Bus) | `secret-tool` (libsecret) |
| Windows | Credential Manager | `cmdkey` + PowerShell (advapi32) |
메타데이터(키 이름, 타임스탬프)는 `~/.envsec/store.sqlite`의 SQLite 데이터베이스에 보관됩니다(`--db` 또는 `ENVSEC_DB`로 구성 가능). 키는 자격 증명 저장소의 서비스/계정 구조에 매핑되는 점 구분자를 하나 이상 포함해야 합니다(예: `service.account`).
## 보안
envsec은 간단한 원칙을 기반으로 구축되었습니다: 비밀은 dotfiles가 아닌 OS에 속합니다. 모든 설계 결정은 그 기반에서 시작됩니다.
### envsec이 비밀을 보호하는 방법
**OS 네이티브 암호화, 맞춤 암호화 없음.** 비밀 값은 macOS Keychain, GNOME Keyring / KDE Wallet 또는 Windows Credential Manager에 직접 저장됩니다. envsec은 자체 암호화를 만들지 않습니다 — 운영 체제가 이미 제공하는 검증된 자격 증명 저장소에 위임하며, 사용자 세션과(macOS에서는 로그인 키체인) 보호됩니다.
**완전한 유니코드 지원.** 비밀 값은 이모지와 악센트 문자를 포함한 모든 유니코드 문자를 포함할 수 있습니다. 값은 OS 자격 증명 저장소에 저장되기 전에 base64로 인코딩되어 플랫폼별 인코딩 문제(예: macOS `security` CLI의 비ASCII 출력 16진수 인코딩)를 방지합니다. 레거시 평문 비밀은 이전 버전과의 호환성을 위해 투명하게 읽힙니다.
**비밀은 평문으로 디스크에 닿지 않습니다.** 값은 터미널에서 OS 자격 증명 저장소로 직접 이동합니다. 구성 파일, 로그 또는 중간 저장소에 기록되지 않습니다.
**터미널 출력에 비밀 없음.** `list` 및 `search` 명령은 키 이름만 표시합니다 — 값은 절대 출력되지 않습니다. 이렇게 하면 스크롤백 버퍼, 화면 녹화 및 어깨 너머로 보는 범위에서 비밀이 유지되지 않습니다.
**안전한 명령 실행.** `run` 명령은 명령 문자열에 비밀을 보간하는 대신 하위 프로세스의 환경 변수로 비밀을 주입합니다. 즉, 비밀 값이 `ps` 출력이나 셸 기록에 나타나지 않습니다. 참조된 비밀이 누락되면 명령이 완전히 차단됩니다 — 불완전한 자격 증명으로 부분 실행되지 않습니다.
**입력 검증 및 주입 방지.** 컨텍스트 이름은 경로 탐색 및 프로토타입 오염 검사와 함께 엄격한 허용 목록(영숫자, 점, 하이픈, 밑줄)에 대해 검증됩니다. 모든 SQLite 쿼리는 SQL 주입을 방지하기 위해 바인드 매개변수가 있는 준비된 문을 사용합니다. Windows의 PowerShell 인수는 명령 주입을 방지하기 위해 이스케이프됩니다.
**제한적인 파일 권한.** 메타데이터 디렉터리(`~/.envsec/`)는 `0700` 권한으로, SQLite 데이터베이스는 `0600` 권한으로 생성되어 소유 사용자로 접근이 제한됩니다.
### 알려진 제한 사항 및 개선 영역
envsec이 아직 다루지 않는 부분에 대해 솔직하게 말씀드립니다. 이는 버그가 아닌 실제 트레이드오프이며 — 이를 이해하면 정보에 입각한 결정을 내리는 데 도움이 됩니다.
**메타데이터가 표시됩니다.** `~/.envsec/store.sqlite`의 SQLite 데이터베이스는 키 이름, 컨텍스트 이름 및 타임스탬프를 저장합니다 — 비밀 값은 절대 저장하지 않지만, 어떤 비밀이 존재하는지 *알 수 있을* 정도로 충분합니다. 저장된 명령 템플릿(`{key}` 플레이스홀더 포함)도 여기에 저장됩니다. 메타데이터 기밀성이 중요하다면 홈 디렉터리가 암호화된 볼륨에 있는지 확인하세요.
**`env-file` 내보내기는 평문입니다.** `env-file` 명령은 비밀 값을 디스크의 `.env` 파일에 씁니다. 이는 본질적으로 민감합니다 — 출력 파일을 그에 따라 취급하고 버전 관리에 절대 커밋하지 마세요. 저장 메커니즘이 아닌 편의 브리지로 간주하세요.
**셸 실행은 본질적인 위험을 수반합니다.** `run` 명령은 명령 템플릿을 `/bin/sh`(Windows에서는 `cmd.exe`)로 전달합니다. 템플릿 자체가 신뢰할 수 없는 입력에서 온 경우 셸 주입이 가능합니다. 직접 작성했거나 신뢰하는 명령 템플릿만 실행하세요.
**컨텍스트 간 접근 제어 없음.** OS 사용자로 실행되는 모든 프로세스는 모든 컨텍스트의 모든 비밀을 읽을 수 있습니다. envsec은 OS 수준 사용자 격리에 의존합니다 — 컨텍스트 간에 자체 권한 부여 계층을 추가하지 않습니다.
**Linux 헤드리스 환경.** Linux에서 envsec은 활성 D-Bus 세션과 키링 데몬(예: `gnome-keyring-daemon`)에 의존합니다. 그래픽 세션이 없는 컨테이너나 헤드리스 서버에서는 키링을 사용할 수 없거나 더 약한 보호로 비밀을 저장할 수 있습니다.
**암호화는 OS에 의존합니다.** envsec은 네이티브 자격 증명 저장소가 제공하는 것 이상의 추가 저장 시 암호화를 추가하지 않습니다. 전체 디스크 암호화가 없는 시스템에서는 물리적 접근 권한이 있는 공격자가 키체인에서 비밀을 추출할 수 있습니다. 가장 강력한 보호를 위해 전체 디스크 암호화(FileVault, LUKS, BitLocker)를 활성화하는 것이 좋습니다.
## 개발
### 사전 요구 사항
- Node.js >= 22
- pnpm
코어, SDK, CLI 및 TUI 패키지는 Effect 4를 사용하며 현재
`4.0.0-rc.112`에 고정되어 있습니다. Effect 4가 릴리스 후보 상태로 유지되는 동안
워크스페이스 전체에서 Effect 및 `@effect/platform-node` 버전을
정렬된 상태로 유지하세요.
### 설정```bash
git clone https://github.com/davidnussio/envsec.git
cd envsec
pnpm install
pnpm run build
packages/
cli/ → envsec CLI (published as envsec)
sdk/ → Node.js/Bun SDK (published as @envsec/sdk)
core/ → Core engine, shared by CLI and SDK (published as @envsec/core)
tui/ → Interactive terminal UI (published as @envsec/tui)
apps/
website/ → Documentation website
### 일반적인 명령어```bash
# Build all packages
pnpm run build
# Lint and format check (all packages)
pnpm run check
# Auto-fix lint and formatting
pnpm run fix
# Run package unit and contract tests
pnpm run test:unit
# Run the CLI end-to-end suite with isolated database and credential fixtures
pnpm --filter envsec test
# Release (build + changeset publish)
pnpm run release
격리된 E2E 스위트는 네이티브 자격 증명 저장소에 절대 접근하지 않습니다. macOS 또는 Linux에서 실제 OS 어댑터를 테스트하려면 먼저 빌드한 후 명시적으로 옵트인하세요:```bash
ENVSEC_E2E_CLI="$PWD/packages/cli/dist/main.js"
ENVSEC_E2E_ISOLATED=0
pnpm --filter envsec test
네이티브 E2E 테스트는 전용 `test.e2e*` 컨텍스트를 사용하며 이후 이를 제거합니다.
### 설치 없이 로컬에서 실행하기
임시 별칭을 생성하여 로컬 빌드를 전역 설치된 것처럼 사용합니다:```bash
# Bash / Zsh
alias envsec="node $(pwd)/packages/cli/dist/main.js"
# Fish
alias envsec "node (pwd)/packages/cli/dist/main.js"
빌드 및 별칭 설정 후, 현재 세션에서 완성 기능을 로드하세요:```bash
alias envsec="node $(pwd)/packages/cli/dist/main.js" eval "$(envsec --completions bash)"
alias envsec="node $(pwd)/packages/cli/dist/main.js" eval "$(envsec --completions zsh)"
alias envsec "node (pwd)/packages/cli/dist/main.js" envsec --completions fish | source
그런 다음 `envsec -c ` 뒤에서 TAB을 눌러 컨텍스트를 확인하거나, `envsec -c myapp.dev get ` 뒤에서 TAB을 눌러 시크릿 키를 확인할 수 있습니다.
### 테스트 실행
엔드투엔드 통합 테스트는 전체 CLI 수명 주기(add, get, list, search, env-file, load, delete, run, cmd, audit, share, completions)를 다룹니다.```bash
# Build first
pnpm run build
# macOS / Linux
bash packages/cli/test/e2e-test.sh
# Windows (PowerShell)
pwsh packages/cli/test/e2e-test.ps1
CI는 GitHub Actions를 통해 main 브랜치로의 push/PR 시 자동으로 실행되며, macOS와 Ubuntu에서는 e2e-test.sh를, Windows에서는 e2e-test.ps1을 실행합니다.
MIT
| 패키지 | 설명 | npm |
|---|
envsec | 비밀 관리용 CLI 도구 | |
@envsec/sdk | 프로그래밍 방식으로 비밀을 로드하는 Node.js / Bun SDK | |
@envsec/core | 핵심 엔진 — OS 자격 증명 저장소 어댑터 + 메타데이터 DB | |
@envsec/tui | 비밀 관리를 위한 대화형 터미널 UI |