@env-master/sdk
v0.1.5
Published
Service SDK: fetch secrets over a machine identity
Readme
@env-master/sdk
Клиент для сервисов: забирает секреты и переменные окружения при старте и держит их в памяти процесса. Значения расшифровываются на стороне клиента — сервер отдаёт шифртекст и data key, обёрнутый под ключ вашей machine identity.
Установка
bun add @env-master/sdk # или npm i @env-master/sdkБыстрый старт
import { EnvMasterClient } from "@env-master/sdk";
const client = new EnvMasterClient({
baseUrl: process.env.ENVMASTER_URL!,
project: "billing-api",
environment: "production",
});
await client.loginMachine({
clientId: process.env.ENVMASTER_CLIENT_ID!,
clientSecret: process.env.ENVMASTER_CLIENT_SECRET!,
});
const dbPassword = await client.get("DB_PASSWORD");Это и есть рекомендуемый способ: аксессор get() вместо записи в process.env.
Переменные окружения видны через /proc, наследуются дочерними процессами и
попадают в crash-дампы, поэтому injectIntoEnv() существует, но требует
осознанного вызова и печатает предупреждение.
Регистрация ключа
Клиент генерирует x25519-пару при создании и выставляет публичную часть в
client.publicKey. Сервер оборачивает data key именно под неё. При enrollment
ключ передаётся в момент обмена одноразового токена; при universal-логине —
регистрируется на первом входе.
API
| Метод | Что делает |
|---|---|
| loginMachine(creds) | Логин по client_id/client_secret; заводит фоновое обновление токена |
| get(key) | Значение одного ключа; бросает NOT_FOUND, если его нет |
| getVersion(key) | Значение вместе с номером версии — чтобы замечать ротацию |
| secrets() | Map<string, string> со всеми значениями |
| list() | Записи с метаданными: kind, visibility, версия, срок годности |
| refresh() | Сбросить кэш и перечитать с сервера |
| validateEnvironment(schema) | Проверка полноты окружения по схеме (значения остаются у клиента) |
| getEnvironmentSchema() | Схема, сохранённая в сервисе |
| mask(text) | Заменяет известные значения на *** — для логов |
| injectIntoEnv({ include }) | Opt-in запись в process.env |
| dispose() | Остановить таймер обновления токена, чтобы процесс мог завершиться |
Ротация и обновление токена
Access-токен обновляется автоматически на 75% его TTL (renewFraction), а кэш
записей живёт cacheTtlMs — по умолчанию 15 минут. При 401 клиент перелогинивается и
повторяет запрос — иначе ротация секрета превращалась бы в инцидент.
Чтобы среагировать на новое значение без перезапуска, сравнивайте версию:
const { value, version } = await client.getVersion("DB_PASSWORD");
if (version !== lastSeenVersion) await reconnectPool(value);Логи
client.mask(text) подставляет *** вместо известных значений (более длинные
заменяются первыми, чтобы не оставить хвост от вложенной подстроки). Ошибки SDK
санитизированы, значения в них не попадают.
Завершение
process.on("SIGTERM", () => {
client.dispose();
});