Управление секретами, шифрование, ротация, инструменты
Secrets Management: управление секретами, шифрование, ротация ключей и инструменты. Безопасное хранение паролей, API ключей, сертификатов.
Secrets Management - Управление секретами
Что такое Secrets Management?
Secrets Management — это процесс безопасного хранения, управления и контроля доступа к конфиденциальной информации, такой как пароли, API ключи, сертификаты, токены и другие секреты.
Ключевые принципы
- Encryption at Rest — шифрование в покое
- Encryption in Transit — шифрование в передаче
- Access Control — контроль доступа
- Audit Logging — аудит доступа
- Rotation — ротация секретов
Типы секретов
1. Аутентификационные данные
- Пароли — пользовательские пароли
- API ключи — ключи для API
- Токены — JWT, OAuth токены
- Сертификаты — SSL/TLS сертификаты
2. Криптографические ключи
- Симметричные ключи — AES ключи
- Асимметричные ключи — RSA ключи
- Ключи подписи — ключи для цифровой подписи
- Мастер-ключи — ключи для шифрования других ключей
3. Конфигурационные данные
- Строки подключения — к базам данных
- Конфигурации — настройки приложений
- Переменные окружения — чувствительные переменные
- Секреты приложений — внутренние секреты
Примеры реализации
1. Базовая система управления секретами
// Базовая система управления секретами
class SecretsManager {
constructor() {
this.secrets = new Map();
this.encryption = new EncryptionManager();
this.accessControl = new AccessControlManager();
this.auditLogger = new AuditLogger();
}
// Создание секрета
async createSecret(secretId, secretValue, metadata = {}) {
try {
// Валидация секрета
this.validateSecret(secretValue);
// Шифрование секрета
const encryptedSecret = await this.encryption.encrypt(secretValue);
// Создание записи секрета
const secret = {
id: secretId,
value: encryptedSecret,
metadata: {
...metadata,
createdAt: new Date(),
updatedAt: new Date(),
version: 1,
},
accessCount: 0,
lastAccessed: null,
};
// Сохранение секрета
this.secrets.set(secretId, secret);
// Аудит
await this.auditLogger.log("SECRET_CREATED", {
secretId: secretId,
metadata: metadata,
});
return {
success: true,
secretId: secretId,
message: "Secret created successfully",
};
} catch (error) {
console.error("Error creating secret:", error);
return {
success: false,
error: error.message,
};
}
}
// Получение секрета
async getSecret(secretId, requester) {
try {
// Проверка доступа
if (!(await this.accessControl.hasAccess(requester, secretId))) {
throw new Error("Access denied");
}
// Получение секрета
const secret = this.secrets.get(secretId);
if (!secret) {
throw new Error("Secret not found");
}
// Расшифровка секрета
const decryptedSecret = await this.encryption.decrypt(secret.value);
// Обновление статистики
secret.accessCount++;
secret.lastAccessed = new Date();
// Аудит
await this.auditLogger.log("SECRET_ACCESSED", {
secretId: secretId,
requester: requester,
accessCount: secret.accessCount,
});
return {
success: true,
value: decryptedSecret,
metadata: secret.metadata,
};
} catch (error) {
console.error("Error getting secret:", error);
return {
success: false,
error: error.message,
};
}
}
// Обновление секрета
async updateSecret(secretId, newValue, requester) {
try {
// Проверка доступа
if (!(await this.accessControl.hasAccess(requester, secretId))) {
throw new Error("Access denied");
}
// Получение существующего секрета
const secret = this.secrets.get(secretId);
if (!secret) {
throw new Error("Secret not found");
}
// Валидация нового секрета
this.validateSecret(newValue);
// Шифрование нового секрета
const encryptedSecret = await this.encryption.encrypt(newValue);
// Обновление секрета
secret.value = encryptedSecret;
secret.metadata.updatedAt = new Date();
secret.metadata.version++;
// Аудит
await this.auditLogger.log("SECRET_UPDATED", {
secretId: secretId,
requester: requester,
version: secret.metadata.version,
});
return {
success: true,
message: "Secret updated successfully",
};
} catch (error) {
console.error("Error updating secret:", error);
return {
success: false,
error: error.message,
};
}
}
// Удаление секрета
async deleteSecret(secretId, requester) {
try {
// Проверка доступа
if (!(await this.accessControl.hasAccess(requester, secretId))) {
throw new Error("Access denied");
}
// Получение секрета
const secret = this.secrets.get(secretId);
if (!secret) {
throw new Error("Secret not found");
}
// Удаление секрета
this.secrets.delete(secretId);
// Аудит
await this.auditLogger.log("SECRET_DELETED", {
secretId: secretId,
requester: requester,
});
return {
success: true,
message: "Secret deleted successfully",
};
} catch (error) {
console.error("Error deleting secret:", error);
return {
success: false,
error: error.message,
};
}
}
// Валидация секрета
validateSecret(secret) {
if (!secret || typeof secret !== "string") {
throw new Error("Invalid secret format");
}
if (secret.length < 8) {
throw new Error("Secret too short");
}
if (secret.length > 1024) {
throw new Error("Secret too long");
}
}
// Получение списка секретов
async listSecrets(requester) {
try {
const accessibleSecrets = [];
for (const [secretId, secret] of this.secrets) {
if (await this.accessControl.hasAccess(requester, secretId)) {
accessibleSecrets.push({
id: secretId,
metadata: secret.metadata,
accessCount: secret.accessCount,
lastAccessed: secret.lastAccessed,
});
}
}
return {
success: true,
secrets: accessibleSecrets,
};
} catch (error) {
console.error("Error listing secrets:", error);
return {
success: false,
error: error.message,
};
}
}
}
2. Система шифрования
// Система шифрования для секретов
class EncryptionManager {
constructor() {
this.crypto = require("crypto");
this.masterKey = null;
}
// Инициализация мастер-ключа
async initialize() {
if (!this.masterKey) {
this.masterKey = await this.generateMasterKey();
}
}
// Генерация мастер-ключа
async generateMasterKey() {
return this.crypto.randomBytes(32);
}
// Шифрование секрета
async encrypt(secret) {
try {
await this.initialize();
// Генерация IV
const iv = this.crypto.randomBytes(16);
// Создание шифра
const cipher = this.crypto.createCipher("aes-256-gcm", this.masterKey);
cipher.setAAD(Buffer.from("secrets-manager"));
// Шифрование
let encrypted = cipher.update(secret, "utf8", "hex");
encrypted += cipher.final("hex");
// Получение тега аутентификации
const authTag = cipher.getAuthTag();
return {
encrypted: encrypted,
iv: iv.toString("hex"),
authTag: authTag.toString("hex"),
algorithm: "aes-256-gcm",
};
} catch (error) {
console.error("Error encrypting secret:", error);
throw new Error("Encryption failed");
}
}
// Расшифровка секрета
async decrypt(encryptedSecret) {
try {
await this.initialize();
// Создание дешифра
const decipher = this.crypto.createDecipher(
"aes-256-gcm",
this.masterKey
);
decipher.setAAD(Buffer.from("secrets-manager"));
decipher.setAuthTag(Buffer.from(encryptedSecret.authTag, "hex"));
// Расшифровка
let decrypted = decipher.update(encryptedSecret.encrypted, "hex", "utf8");
decrypted += decipher.final("utf8");
return decrypted;
} catch (error) {
console.error("Error decrypting secret:", error);
throw new Error("Decryption failed");
}
}
// Ротация мастер-ключа
async rotateMasterKey() {
try {
const oldMasterKey = this.masterKey;
const newMasterKey = await this.generateMasterKey();
// Перешифровка всех секретов с новым ключом
await this.reencryptAllSecrets(oldMasterKey, newMasterKey);
// Обновление мастер-ключа
this.masterKey = newMasterKey;
// Очистка старого ключа
this.clearKey(oldMasterKey);
return {
success: true,
message: "Master key rotated successfully",
};
} catch (error) {
console.error("Error rotating master key:", error);
throw new Error("Master key rotation failed");
}
}
// Перешифровка всех секретов
async reencryptAllSecrets(oldKey, newKey) {
// Реализация перешифровки всех секретов
// Это упрощенная версия - в реальной системе нужно
// перешифровать все секреты в базе данных
console.log("Re-encrypting all secrets with new master key");
}
// Очистка ключа из памяти
clearKey(key) {
if (key) {
key.fill(0);
}
}
}
3. Система контроля доступа
// Система контроля доступа для секретов
class AccessControlManager {
constructor() {
this.permissions = new Map();
this.roles = new Map();
this.users = new Map();
}
// Создание роли
createRole(roleId, permissions) {
const role = {
id: roleId,
permissions: permissions,
createdAt: new Date(),
};
this.roles.set(roleId, role);
return {
success: true,
role: role,
};
}
// Назначение роли пользователю
assignRole(userId, roleId) {
if (!this.users.has(userId)) {
this.users.set(userId, {
id: userId,
roles: [],
createdAt: new Date(),
});
}
const user = this.users.get(userId);
if (!user.roles.includes(roleId)) {
user.roles.push(roleId);
}
return {
success: true,
message: "Role assigned successfully",
};
}
// Проверка доступа к секрету
async hasAccess(userId, secretId) {
try {
const user = this.users.get(userId);
if (!user) {
return false;
}
// Проверка ролей пользователя
for (const roleId of user.roles) {
const role = this.roles.get(roleId);
if (role && this.hasPermission(role, secretId)) {
return true;
}
}
// Проверка прямых разрешений
const directPermission = this.permissions.get(`${userId}:${secretId}`);
if (directPermission) {
return true;
}
return false;
} catch (error) {
console.error("Error checking access:", error);
return false;
}
}
// Проверка разрешения роли
hasPermission(role, secretId) {
if (!role.permissions) {
return false;
}
// Проверка на полный доступ
if (role.permissions.includes("*")) {
return true;
}
// Проверка на доступ к конкретному секрету
if (role.permissions.includes(secretId)) {
return true;
}
// Проверка на доступ по паттерну
for (const permission of role.permissions) {
if (permission.includes("*")) {
const pattern = permission.replace("*", ".*");
const regex = new RegExp(pattern);
if (regex.test(secretId)) {
return true;
}
}
}
return false;
}
// Предоставление прямого доступа
grantAccess(userId, secretId) {
const permissionKey = `${userId}:${secretId}`;
this.permissions.set(permissionKey, {
userId: userId,
secretId: secretId,
grantedAt: new Date(),
});
return {
success: true,
message: "Access granted successfully",
};
}
// Отзыв доступа
revokeAccess(userId, secretId) {
const permissionKey = `${userId}:${secretId}`;
this.permissions.delete(permissionKey);
return {
success: true,
message: "Access revoked successfully",
};
}
}
4. Система аудита
// Система аудита для секретов
class AuditLogger {
constructor() {
this.logs = [];
this.maxLogs = 10000;
}
// Логирование события
async log(eventType, data) {
try {
const logEntry = {
id: this.generateLogId(),
timestamp: new Date(),
eventType: eventType,
data: data,
level: this.getLogLevel(eventType),
};
// Добавление лога
this.logs.push(logEntry);
// Ограничение количества логов
if (this.logs.length > this.maxLogs) {
this.logs.shift();
}
// Вывод в консоль для демонстрации
console.log(`[AUDIT] ${eventType}:`, data);
return {
success: true,
logId: logEntry.id,
};
} catch (error) {
console.error("Error logging event:", error);
return {
success: false,
error: error.message,
};
}
}
// Получение логов
getLogs(filter = {}) {
let filteredLogs = this.logs;
// Фильтрация по типу события
if (filter.eventType) {
filteredLogs = filteredLogs.filter(
(log) => log.eventType === filter.eventType
);
}
// Фильтрация по уровню
if (filter.level) {
filteredLogs = filteredLogs.filter((log) => log.level === filter.level);
}
// Фильтрация по дате
if (filter.startDate) {
filteredLogs = filteredLogs.filter(
(log) => log.timestamp >= filter.startDate
);
}
if (filter.endDate) {
filteredLogs = filteredLogs.filter(
(log) => log.timestamp <= filter.endDate
);
}
// Сортировка по дате
filteredLogs.sort((a, b) => b.timestamp - a.timestamp);
return {
success: true,
logs: filteredLogs,
total: filteredLogs.length,
};
}
// Получение уровня лога
getLogLevel(eventType) {
const levelMap = {
SECRET_CREATED: "INFO",
SECRET_ACCESSED: "INFO",
SECRET_UPDATED: "INFO",
SECRET_DELETED: "WARN",
ACCESS_DENIED: "WARN",
UNAUTHORIZED_ACCESS: "ERROR",
MASTER_KEY_ROTATED: "INFO",
};
return levelMap[eventType] || "INFO";
}
// Генерация ID лога
generateLogId() {
return "log-" + Math.random().toString(36).substr(2, 9);
}
// Экспорт логов
exportLogs(format = "json") {
try {
let exportData;
switch (format) {
case "json":
exportData = JSON.stringify(this.logs, null, 2);
break;
case "csv":
exportData = this.convertToCSV(this.logs);
break;
default:
throw new Error("Unsupported format");
}
return {
success: true,
data: exportData,
format: format,
};
} catch (error) {
console.error("Error exporting logs:", error);
return {
success: false,
error: error.message,
};
}
}
// Конвертация в CSV
convertToCSV(logs) {
if (logs.length === 0) {
return ";
}
const headers = ["id", "timestamp", "eventType", "level", "data"];
const csvRows = [headers.join(",")];
for (const log of logs) {
const row = [
log.id,
log.timestamp.toISOString(),
log.eventType,
log.level,
JSON.stringify(log.data).replace(/"/g, '"'),
];
csvRows.push(row.join(","));
}
return csvRows.join("\n");
}
}
Ротация секретов
1. Автоматическая ротация
// Система автоматической ротации секретов
class SecretRotationManager {
constructor(secretsManager) {
this.secretsManager = secretsManager;
this.rotationPolicies = new Map();
this.rotationJobs = new Map();
}
// Создание политики ротации
createRotationPolicy(secretId, policy) {
const rotationPolicy = {
secretId: secretId,
interval: policy.interval, // в миллисекундах
autoRotate: policy.autoRotate || false,
notifyBefore: policy.notifyBefore || 24 * 60 * 60 * 1000, // 24 часа
lastRotated: null,
nextRotation: null,
};
this.rotationPolicies.set(secretId, rotationPolicy);
// Планирование ротации
if (rotationPolicy.autoRotate) {
this.scheduleRotation(secretId);
}
return {
success: true,
policy: rotationPolicy,
};
}
// Планирование ротации
scheduleRotation(secretId) {
const policy = this.rotationPolicies.get(secretId);
if (!policy) {
return;
}
const nextRotation = new Date(Date.now() + policy.interval);
policy.nextRotation = nextRotation;
// Создание задачи ротации
const jobId = this.generateJobId();
const job = {
id: jobId,
secretId: secretId,
scheduledTime: nextRotation,
status: "SCHEDULED",
};
this.rotationJobs.set(jobId, job);
// Уведомление перед ротацией
const notifyTime = new Date(nextRotation.getTime() - policy.notifyBefore);
setTimeout(() => {
this.notifyBeforeRotation(secretId);
}, notifyTime.getTime() - Date.now());
// Выполнение ротации
setTimeout(() => {
this.executeRotation(secretId);
}, policy.interval);
return jobId;
}
// Выполнение ротации
async executeRotation(secretId) {
try {
const policy = this.rotationPolicies.get(secretId);
if (!policy) {
throw new Error("Rotation policy not found");
}
// Генерация нового секрета
const newSecret = await this.generateNewSecret(secretId);
// Обновление секрета
const result = await this.secretsManager.updateSecret(
secretId,
newSecret,
"system"
);
if (result.success) {
// Обновление политики
policy.lastRotated = new Date();
policy.nextRotation = new Date(Date.now() + policy.interval);
// Планирование следующей ротации
if (policy.autoRotate) {
this.scheduleRotation(secretId);
}
// Уведомление о ротации
await this.notifyRotationComplete(secretId);
return {
success: true,
message: "Secret rotated successfully",
};
} else {
throw new Error(result.error);
}
} catch (error) {
console.error("Error rotating secret:", error);
await this.notifyRotationFailed(secretId, error.message);
return {
success: false,
error: error.message,
};
}
}
// Генерация нового секрета
async generateNewSecret(secretId) {
// Логика генерации нового секрета в зависимости от типа
const crypto = require("crypto");
return crypto.randomBytes(32).toString("hex");
}
// Уведомление перед ротацией
async notifyBeforeRotation(secretId) {
console.log(`[NOTIFICATION] Secret ${secretId} will be rotated soon`);
// Реализация уведомления (email, Slack, etc.)
}
// Уведомление о завершении ротации
async notifyRotationComplete(secretId) {
console.log(`[NOTIFICATION] Secret ${secretId} rotated successfully`);
// Реализация уведомления
}
// Уведомление об ошибке ротации
async notifyRotationFailed(secretId, error) {
console.log(`[NOTIFICATION] Secret ${secretId} rotation failed: ${error}`);
// Реализация уведомления
}
// Генерация ID задачи
generateJobId() {
return "job-" + Math.random().toString(36).substr(2, 9);
}
}
Best Practices
1. Безопасность
- Шифрование — всегда шифруйте секреты
- Контроль доступа — ограничивайте доступ к секретам
- Аудит — ведите логи всех операций
- Ротация — регулярно обновляйте секреты
2. Управление
- Централизация — используйте централизованное хранилище
- Версионирование — ведите версии секретов
- Мониторинг — отслеживайте использование секретов
- Автоматизация — автоматизируйте процессы
3. Интеграция
- CI/CD — интегрируйте с процессами разработки
- Мониторинг — интегрируйте с системами мониторинга
- Уведомления — настройте уведомления о событиях
- Backup — создавайте резервные копии
Заключение
Secrets Management — это критически важный компонент кибербезопасности, который требует:
- Правильной архитектуры — безопасное хранение и передача
- Строгого контроля доступа — ограничение доступа к секретам
- Непрерывного мониторинга — отслеживание использования
- Автоматизации процессов — ротация и управление
Помните: управление секретами — это не разовое мероприятие, а постоянный процесс. Регулярно пересматривайте политики, обновляйте технологии и следите за новыми угрозами.
Совет: Начните с централизации хранения секретов, затем внедрите шифрование и контроль доступа. Не забывайте о ротации секретов и мониторинге их использования!