
네이티브 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
### Input
RackShift가 에이전트를 시작하고 작업을 기다립니다.```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 도구를 통해 사용합니다.
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
A running D-Bus session and a keyring daemon (e.g. `gnome-keyring-daemon`) must be active. Most desktop environments handle this automatically.
### Windows
No extra dependencies. Uses the built-in Windows Credential Manager via `cmdkey` and PowerShell.
## Installation
### 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
## Usage
Most commands require a context specified with `--context` (or `-c`).
A context is a free-form label for grouping secrets — e.g. `myapp.dev`, `stripe-api.prod`, `work.staging`.
### Global options
These options are available on all commands:
- `--context`, `-c` — Context name (e.g. `myapp.dev`, `stripe-api.prod`). Also reads `ENVSEC_CONTEXT` env var
- `--debug`, `-d` — Enable debug logging
- `--json` — Output in JSON format for scripting
- `--db` — Path to SQLite database file (default: `~/.envsec/store.sqlite`). Also reads `ENVSEC_DB` env var
### Custom database path
By default, metadata is stored at `~/.envsec/store.sqlite`. You can override this with `--db` or the `ENVSEC_DB` environment variable:```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
The --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
### 비밀 가져오기
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
glob 패턴을 사용하여 시크릿 또는 컨텍스트를 검색합니다.
<pattern> — 검색할 Glob 패턴 (예: api.*, myapp.*)--json — JSON 형식으로 출력```bashenvsec -c myapp.dev search "api.*"
envsec search "myapp.*"
### 컨텍스트 간 시크릿 이동
한 컨텍스트에서 다른 컨텍스트로 시크릿을 이동합니다. 이동 후 소스 시크릿은 제거됩니다.
- `<pattern>` — 이동할 글로브 패턴 또는 정확한 키 (`--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 목록
모든 저장된 명령어를 나열합니다.```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/remove 명령 출력```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
Supported shells: `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
입력 텍스트가 비어 있습니다. 번역할 내용이 없습니다. Kitploit 도구 콘텐츠(청크 53/83)를 포함해 다시 제출해 주십시오.``` ▶ 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.
- [tests](https://github.com/davidnussio/envsec/blob/HEAD/tools/Public-IoT-Vulnerability-Scanner-Research/docs/tests.md)에서 테스트케이스를 확인할 수 있습니다.```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
The variable ENVSEC_CONTEXT is always set inside the session, so you can
reference it in scripts or prompt customizations.
.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` 파일이 더 이상 디스크에 존재하지 않으면, 감사는 자동으로 메타데이터에서 제거하고 정리를 보고합니다.
### 임의의 비밀 생성
암호학적으로 안전한 임의의 비밀을 생성하고, 선택적으로 저장합니다.
- `<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_"
When both context and key are provided, the generated value is stored and printed. Without either, the raw value goes to stdout — useful for piping to pbcopy, xclip, or other tools.
envsec tui
envsec -c myapp.dev tui
TUI는 메인 메뉴에서 접근 가능한 8개의 화면을 제공합니다:
- **컨텍스트** — 모든 컨텍스트 탐색, `s`로 활성 컨텍스트 설정, `x`로 컨텍스트 지우기, 비밀 수 확인, 전체 컨텍스트 삭제
- **비밀** — 테이블에서 비밀 목록 보기, 값 표시, 비밀 추가 또는 삭제
- **비밀 추가** — 마스킹된 입력과 선택적 만료 기간이 있는 대화형 폼
- **검색** — 비밀 또는 컨텍스트에서 글로브 패턴 검색
- **저장된 명령** — 저장된 명령 템플릿 목록, 보기, 삭제
- **감사** — 만료되었거나 곧 만료되는 비밀 확인, 추적된 `.env` 파일 내보내기 검토
- **.env 가져오기** — `.env` 파일에서 현재 컨텍스트로 비밀 로드
- **.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
The doctor 명령어는 envsec 설치가 올바르게 작동하는지 확인합니다. 다음 항목을 점검합니다:
ENVSEC_DB, ENVSEC_CONTEXT)envsec는 bash, zsh, fish에서 동적 탭 완성을 지원합니다. 자동 완성은 컨텍스트 인식 방식으로, 메타데이터 데이터베이스를 실시간으로 조회하여 실제 컨텍스트 이름, 시크릿 키, 저장된 명령어 이름을 제안합니다.```bash
eval "$(envsec --completions bash)"
eval "$(envsec --completions zsh)"
envsec --completions fish | source
What gets completed dynamically:
- `--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` (충돌 감지 포함) | N/A — `.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` | 암호화된 `.env` 파일을 git에 커밋 (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는 그 중간에 위치합니다 — 계정이 없고, 클라우드 의존성이 없으며, `.env` 파일로 할 수 있는 것 이상의 개발자 중심 워크플로를 제공하는 OS 네이티브 암호화를 제공합니다.
## 작동 원리
비밀은 네이티브 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` ( `--db` 또는 `ENVSEC_DB`로 구성 가능)의 SQLite 데이터베이스에 보관됩니다. 키는 자격 증명 저장소의 서비스/계정 구조에 매핑되는 최소한 하나의 점 구분자를 포함해야 합니다(예: `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
### 설정```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
# Release (build + changeset publish)
pnpm run release
로컬 빌드를 마치 전역에 설치된 것처럼 사용할 수 있도록 임시 별칭을 생성합니다:```bash
alias envsec="node $(pwd)/packages/cli/dist/main.js"
alias envsec "node (pwd)/packages/cli/dist/main.js"
### 로컬에서 셸 완성 테스트하기
빌드 및 alias 설정 후, 현재 세션에서 완성 기능을 로드하십시오:```bash
# Bash
alias envsec="node $(pwd)/packages/cli/dist/main.js"
eval "$(envsec --completions bash)"
# Zsh
alias envsec="node $(pwd)/packages/cli/dist/main.js"
eval "$(envsec --completions zsh)"
# Fish
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
pnpm run build
bash packages/cli/test/e2e-test.sh
pwsh packages/cli/test/e2e-test.ps1
CI는 GitHub Actions를 통해 `main` 브랜치에 push/PR이 발생하면 자동으로 실행되며, macOS와 Ubuntu에서는 `e2e-test.sh`, Windows에서는 `e2e-test.ps1`을 실행합니다.
## 라이선스
MIT
| Package | Description | npm |
|---|
envsec | 비밀 관리 CLI 도구 | |
@envsec/sdk | 프로그래밍 방식으로 비밀을 로드하는 Node.js / Bun SDK | |
@envsec/core | 핵심 엔진 — OS 자격 증명 저장소 어댑터 + 메타데이터 DB | |
@envsec/tui | 대화형 터미널 UI for 비밀 관리 |