Управление секретами, шифрование, ротация, инструменты

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 — это критически важный компонент кибербезопасности, который требует:

  • Правильной архитектуры — безопасное хранение и передача
  • Строгого контроля доступа — ограничение доступа к секретам
  • Непрерывного мониторинга — отслеживание использования
  • Автоматизации процессов — ротация и управление

Помните: управление секретами — это не разовое мероприятие, а постоянный процесс. Регулярно пересматривайте политики, обновляйте технологии и следите за новыми угрозами.


Совет: Начните с централизации хранения секретов, затем внедрите шифрование и контроль доступа. Не забывайте о ротации секретов и мониторинге их использования!