운영체제의 네이티브 자격 증명 저장소 API 를 사용하여 민감한 자격 증명을 안전하게 저장하고 검색합니다.
typescript
import { secrets } from "bun";
let githubToken: string | null = await secrets.get({
service: "my-cli-tool",
name: "github-token",
});
if (!githubToken) {
githubToken = prompt("GitHub 토큰을 입력하세요");
await secrets.set({
service: "my-cli-tool",
name: "github-token",
value: githubToken,
});
console.log("GitHub 토큰 저장됨");
}
const response = await fetch("https://api.github.com/user", {
headers: { Authorization: `token ${githubToken}` },
});
console.log(`로그인 사용자: ${(await response.json()).login}`);개요
Bun.secrets 는 CLI 도구와 개발 애플리케이션이 일반적으로 ~/.npmrc, ~/.aws/credentials 또는 .env 파일과 같은 일반 텍스트 파일에 저장하는 민감한 자격 증명을 관리하기 위한 크로스 플랫폼 API 를 제공합니다. 다음을 사용합니다:
- macOS: Keychain Services
- Linux: libsecret (GNOME Keyring, KWallet 등)
- Windows: Windows Credential Manager
모든 작업은 비동기이며 논블로킹으로, Bun 의 스레드풀에서 실행됩니다.
NOTE
향후 프로덕션 배포 비밀에 더 적합하도록 추가 `provider` 옵션을 추가할 수 있지만, 현재 이 API 는 주로 로컬 개발 도구에 유용합니다.API
Bun.secrets.get(options)
저장된 자격 증명을 검색합니다.
typescript
import { secrets } from "bun";
const password = await Bun.secrets.get({
service: "my-app",
name: "alice@example.com",
});
// 반환: string | null
// 또는 객체 없이 사용 가능
const password = await Bun.secrets.get("my-app", "alice@example.com");파라미터:
options.service(문자열, 필수) - 서비스 또는 애플리케이션 이름options.name(문자열, 필수) - 사용자명 또는 계정 식별자
반환:
Promise<string | null>- 저장된 비밀번호, 없으면null
Bun.secrets.set(options, value)
자격 증명을 저장하거나 업데이트합니다.
typescript
import { secrets } from "bun";
await secrets.set({
service: "my-app",
name: "alice@example.com",
value: "super-secret-password",
});파라미터:
options.service(문자열, 필수) - 서비스 또는 애플리케이션 이름options.name(문자열, 필수) - 사용자명 또는 계정 식별자value(문자열, 필수) - 저장할 비밀번호 또는 비밀
참고:
- 주어진 service/name 조합에 대한 자격 증명이 이미 있으면 교체됩니다
- 저장된 값은 운영체제에 의해 암호화됩니다
Bun.secrets.delete(options)
저장된 자격 증명을 삭제합니다.
typescript
const deleted = await Bun.secrets.delete({
service: "my-app",
name: "alice@example.com",
value: "super-secret-password",
});
// 반환: boolean파라미터:
options.service(문자열, 필수) - 서비스 또는 애플리케이션 이름options.name(문자열, 필수) - 사용자명 또는 계정 식별자
반환:
Promise<boolean>- 자격 증명이 삭제되면true, 없으면false
예제
CLI 도구 자격 증명 저장
javascript
// GitHub CLI 토큰 저장 (~/.config/gh/hosts.yml 대신)
await Bun.secrets.set({
service: "my-app.com",
name: "github-token",
value: "ghp_xxxxxxxxxxxxxxxxxxxx",
});
// 또는 객체 없이 사용 가능
await Bun.secrets.set("my-app.com", "github-token", "ghp_xxxxxxxxxxxxxxxxxxxx");
// npm 레지스트리 토큰 저장 (~/.npmrc 대신)
await Bun.secrets.set({
service: "npm-registry",
name: "https://registry.npmjs.org",
value: "npm_xxxxxxxxxxxxxxxxxxxx",
});
// API 호출을 위해 검색
const token = await Bun.secrets.get({
service: "gh-cli",
name: "github.com",
});
if (token) {
const response = await fetch("https://api.github.com/name", {
headers: {
Authorization: `token ${token}`,
},
});
}일반 텍스트 구성 파일에서 마이그레이션
javascript
// ~/.aws/credentials 에 저장하는 대신
await Bun.secrets.set({
service: "aws-cli",
name: "AWS_SECRET_ACCESS_KEY",
value: process.env.AWS_SECRET_ACCESS_KEY,
});
// 민감한 데이터가 있는 .env 파일 대신
await Bun.secrets.set({
service: "my-app",
name: "api-key",
value: "sk_live_xxxxxxxxxxxxxxxxxxxx",
});
// 런타임에 로드
const apiKey =
(await Bun.secrets.get({
service: "my-app",
name: "api-key",
})) || process.env.API_KEY; // CI/프로덕션용 대체오류 처리
javascript
try {
await Bun.secrets.set({
service: "my-app",
name: "alice",
value: "password123",
});
} catch (error) {
console.error("자격 증명 저장 실패:", error.message);
}
// 자격 증명이 존재하는지 확인
const password = await Bun.secrets.get({
service: "my-app",
name: "alice",
});
if (password === null) {
console.log("자격 증명을 찾을 수 없음");
}자격 증명 업데이트
javascript
// 초기 비밀번호
await Bun.secrets.set({
service: "email-server",
name: "admin@example.com",
value: "old-password",
});
// 새 비밀번호로 업데이트
await Bun.secrets.set({
service: "email-server",
name: "admin@example.com",
value: "new-password",
});
// 이전 비밀번호가 교체됨플랫폼 동작
macOS (Keychain)
- 자격 증명은 사용자의 로그인 키체인에 저장됩니다
- 키체인은 첫 사용 시 접근 권한에 대한 프롬프트를 표시할 수 있습니다
- 자격 증명은 시스템 재시작 후에도 유지됩니다
- 저장한 사용자만 접근할 수 있습니다
Linux (libsecret)
- 비밀 서비스 데몬이 필요합니다 (GNOME Keyring, KWallet 등)
- 자격 증명은 기본 컬렉션에 저장됩니다
- 키링이 잠긴 경우 잠금 해제 프롬프트가 표시될 수 있습니다
- 비밀 서비스가 실행 중이어야 합니다
Windows (Credential Manager)
- 자격 증명은 Windows Credential Manager 에 저장됩니다
- 제어판 → 자격 증명 관리자 → Windows 자격 증명에서 볼 수 있습니다
CRED_PERSIST_ENTERPRISE플래그로 저장되어 사용자별로 범위가 지정됩니다- Windows Data Protection API 를 사용하여 암호화됩니다
보안 고려사항
- 암호화: 자격 증명은 운영체제의 자격 증명 관리자에 의해 암호화됩니다
- 접근 제어: 자격 증명을 저장한 사용자만 검색할 수 있습니다
- 일반 텍스트 없음: 비밀번호는 일반 텍스트로 저장되지 않습니다
- 메모리 안전: Bun 은 사용 후 비밀번호 메모리를 지웁니다
- 프로세스 격리: 자격 증명은 계정 이름별로 격리됩니다
제한 사항
- 최대 비밀번호 길이는 플랫폼에 따라 다릅니다 (일반적으로 2048-4096 바이트)
- 서비스 및 이름 길이는 합리적인 길이 (< 256 자) 여야 합니다
- 플랫폼에 따라 일부 특수 문자는 이스케이프가 필요할 수 있습니다
- 적절한 시스템 서비스가 필요합니다:
- Linux: 비밀 서비스 데몬이 실행 중이어야 함
- macOS: Keychain Access 를 사용할 수 있어야 함
- Windows: Credential Manager 서비스가 활성화되어 있어야 함
환경 변수와의 비교
환경 변수와 달리 Bun.secrets 는:
- ✅ 휴식 상태에서 자격 증명 암호화 (운영체제 덕분에)
- ✅ 프로세스 메모리 덤프에서 비밀 노출 방지 (더 이상 필요하지 않으면 메모리가 지워짐)
- ✅ 애플리케이션 재시작 후에도 유지
- ✅ 애플리케이션 재시작 없이 업데이트 가능
- ✅ 이름 수준의 접근 제어 제공
- ❌ OS 자격 증명 서비스 필요
- ❌ 배포 비밀에는 그다지 유용하지 않음 (프로덕션에서는 환경 변수 사용)
모범 사례
설명적인 서비스 이름 사용: 실제 도구 또는 애플리케이션 이름과 일치시킵니다 외부 사용을 위한 CLI 를 구축하는 경우 서비스 이름에 UTI (Uniform Type Identifier) 를 사용하는 것이 좋습니다.
javascript// 좋음 - 실제 도구와 일치 { service: "com.docker.hub", name: "username" } { service: "com.vercel.cli", name: "team-name" } // 피하기 - 너무 일반적 { service: "api", name: "key" }자격 증명만 저장: 이 API 에 애플리케이션 구성을 저장하지 마십시오 이 API 는 느리므로 일부 작업에는 여전히 구성 파일이 필요합니다.
로컬 개발 도구에 사용:
- ✅ CLI 도구 (gh, npm, docker, kubectl)
- ✅ 로컬 개발 서버
- ✅ 테스트용 개인 API 키
- ❌ 프로덕션 서버 (적절한 비밀 관리 사용)
TypeScript
typescript
namespace Bun {
interface SecretsOptions {
service: string;
name: string;
}
interface Secrets {
get(options: SecretsOptions): Promise<string | null>;
set(options: SecretsOptions, value: string): Promise<void>;
delete(options: SecretsOptions): Promise<boolean>;
}
const secrets: Secrets;
}