Skip to content

ai-native-engineer/agents-env

Repository files navigation

agents-env

AI 코딩 에이전트가 시크릿 값을 노출하지 않고 환경변수를 사용하게 하는 CLI

crates.io license rust

한국어 · English


에이전트에게 API 키를 넘기면 그 값이 대화 로그에 남는다. curl -v 출력이나 에러 스택 한 줄로도 노출된다. agents-env는 값을 자식 프로세스로만 전달하고, 에이전트의 대화 기록에는 키 이름만 남긴다. 스키마나 암호화 vault, 클라우드 계정 없이 기존 .env 위에 바로 얹어 쓴다.

agents-env run TAVILY_API_KEY@work -- curl -H "Authorization: Bearer {{TAVILY_API_KEY}}" https://api/...

{{TAVILY_API_KEY}}는 명령이 실행되는 순간에만 실제 값으로 치환된다. 대화 로그에 남는 것은 {{TAVILY_API_KEY}} 문자열뿐이고, curl이 키를 출력하더라도 [masked:TAVILY_API_KEY]로 가려진 뒤에 나온다.

특징

환경변수·시크릿 관리 도구는 많지만, 값을 AI 대화 로그에 남기지 않으면서 에이전트가 .env를 읽고 쓰게 하는 것은 드물다. 비슷한 도구 14개를 검토했을 때 아래 네 가지를 모두 갖춘 것은 없었다.

  • 출력 마스킹: 주입한 시크릿이 자식의 stdout/stderr에 나타나면 실시간으로 [masked:KEY]로 치환한다. doppler run·infisical run은 주입만 하고 출력은 막지 않는다.
  • 값 비경유 복사: copy는 전역 store의 시크릿을 로컬 .env로 옮기되, 값이 에이전트 컨텍스트를 거치지 않는다.
  • 에이전트 자동 감지: Claude Code와 Codex 환경을 자동 인식해 기본적으로 값을 숨긴다. 수동 플래그가 필요 없다.
  • 비대칭 쓰기 가드: 사람이 관리하는 전역 마스터 .env는 이 도구로 수정할 수 없다.

동작 방식

get은 키를 찾는 명령, run은 키를 쓰는 명령이다. mytool --key "$(agents-env get KEY)"처럼 명령 치환으로 값을 꺼내 쓸 수는 없다. $(...)는 값을 셸 명령줄, 즉 에이전트 컨텍스트로 가져오기 때문에, 에이전트 모드의 get은 값 대신 키 이름과 길이만 반환한다. 값은 run이 자식 프로세스로 직접 전달한다.

마스킹은 출력 스트림(자식 → 호출자)만 처리하고 프로그램이 받는 입력은 바꾸지 않는다. 따라서 프로그램은 실제 값으로 정상 동작하며, 그 값이 출력으로 되돌아올 때만 가려진다.

사용법

명령 설명
get <pattern> 키 조회(부분 일치). 사람에게는 KEY=value, 에이전트에게는 KEY [set, N chars] # tag만 출력.
ls [pattern] 키 이름과 태그. 어떤 모드에서도 값은 출력하지 않음.
run <KEY[@tag]…> -- <cmd> 자식 env에 주입, 출력 마스킹, argv의 {{KEY}} 치환. --all은 스코프 전체 주입.
set <KEY> <VALUE> --to <file> 로컬 파일에 비밀이 아닌 값 기록. 크리덴셜 형태면 경고.
copy <KEY[@tag]…> --to <file> 전역 store의 시크릿을 로컬 파일로 복사. 값은 출력하지 않음. --as NEWKEY로 키 이름 변경.
edit 전역 store를 $EDITOR로 연다. 사람 전용이며 에이전트 모드·비TTY에서는 거부.
doctor 파일 권한, gitignore 커버리지, 오래된 백업, 태그 없는 중복 키, Claude Code deny 규칙 점검.

전체 옵션은 agents-env --help.

스코프와 파일. 기본 스코프는 전역 store다. -l/--local./.env를, -f <name>./<name>을 읽어 .env.local, .env.production 등 여러 파일을 다룬다.

agents-env -f .env.production get DATABASE

중복 키. 한 키에 계정이 여럿이면 인라인 # comment가 태그가 된다. run, copy처럼 결과가 갈리는 작업은 유일 매치를 요구하며, 모호하면 후보 태그(값 제외)를 보여주고 멈춘다.

agents-env copy NOTION_API_KEY@demodev --to .env.local

쓰기 가드

set/copy는 현재 디렉토리의 .env* 파일만 쓴다. 전역 store는 구조적으로 도달할 수 없다.

  • 쓰기 대상을 전역 스코프로 지정하는 플래그가 없다.
  • 파일명은 bare .env/.env.*만 허용한다. 경로 구분자를 막아 ../, 절대경로, .bak 타겟이 차단된다.
  • 타겟이 심볼릭링크거나, 하드링크를 가졌거나, 전역 store와 동일 파일이면 거부한다.
  • 전역 store 디렉토리 내부에서의 쓰기를 거부한다.
  • git 레포 안에서는 시크릿을 쓰는 copy 타겟이 추적되지 않으면서 gitignore되어 있어야 한다. 아니면 하드 에러로 막는다(override 없음, .gitignore 수정 필요).

쓰기 전에는 <file>.YYMMDD.bak 백업을 만든다. 같은 날 두 번째 쓰기부터는 그날의 첫 백업을 유지한다(작업 시작 전 상태가 복구 지점이므로). 이후 O_NOFOLLOW 임시 파일에 쓰고 rename으로 교체한다. 백업도 .env로 시작하므로 .env* gitignore 한 줄로 함께 덮인다.

한계

마스킹은 심층 방어 수단이지 샌드박스가 아니다. 자식이 출력한 시크릿 원문은 잡지만, 자식이 재인코딩한 값(base64, URL 인코딩, 분할)은 잡지 못한다. cat .env나 Claude Code의 @.env 인라인 참조는 이 도구를 우회하며, 그쪽은 하네스 deny 규칙으로 막아야 한다. doctor~/.claude/settings.jsonRead(**/.env) 계열 deny 여부를 점검하므로, 두 레이어가 서로를 보완하도록 함께 설정하는 것을 권한다.

  • 자동 감지는 Claude Code와 Codex만 지원한다. Cursor, Aider, Windsurf, 자체 제작 하네스에서는 에이전트 여부를 인식하지 못한다. 이 경우 get이 값을 출력하고 --no-mask도 허용된다(run의 출력 마스킹 자체는 모든 환경에서 동작한다). 해당 도구에서는 그 환경 셸 설정에 AGENTS_ENV_AGENT_MODE=1을 넣거나 config에 markers=...를 추가해 직접 활성화한다.
  • 감지는 신호이지 차단막이 아니다. 모드는 env 마커로 판단하므로, 에이전트가 마커를 제거하거나(env -u CLAUDECODE …) --no-mask를 써서 사람 모드를 강제할 수 있다. 대상 위협은 실수로 시크릿을 로깅하면 안 되는 정직한 에이전트다. 악의적 에이전트는 ~/.dotfiles/.env를 직접 읽을 수 있으며, 그것은 이 도구가 아니라 deny 규칙이 막을 영역이다.
  • {{KEY}}는 같은 사용자의 ps에 노출된다. 값이 자식 argv에 들어가 같은 사용자의 다른 프로세스가 읽을 수 있다. 공유 머신에서 민감한 값은 {{KEY}} 대신 env 주입을 사용한다.
  • 부모 디렉토리 스왑 TOCTOU. 가드가 cwd를 canonicalize하고 임시 파일에 O_NOFOLLOW를 쓰지만, 같은 사용자 권한의 공격자가 쓰기 도중 부모 디렉토리를 rename하면 우회할 수 있다. 완전한 차단은 디렉토리 fd(openat/renameat) 방식이 필요하며 다음 버전에서 다룬다. 로컬 동일 사용자 쓰기 권한 없이는 도달할 수 없고, 그 권한이 있다면 시크릿은 이미 노출된 상태다.
  • 줄 끝은 LF로 정규화된다. 라운드트립은 주석·순서·간격을 보존하지만 CRLF 파일은 LF로 다시 쓰이고 끝에 개행이 추가된다.

설치

설치와 설정은 함께 배포되는 에이전트 스킬에 포함되어 있어, Claude Code나 Codex에 맡길 수 있다. 수동 설치는 다음과 같다.

cargo install agents-env
# crates.io 등록 전이면:
cargo install --git https://github.com/ai-native-engineer/agents-env

라이선스

MIT

About

Env vars for AI agents: use secrets without ever seeing their values. A zero-config safety layer over your plaintext .env (Rust CLI + Claude Code plugin).

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages