awesome-everything EN
↑ Обратно к восхождению

Безопасность

Управление секретами: чтение кода и конфигов

Суть Чтение реальных конфигов и кода — закоммиченный .env, выборка динамической креды из Vault, хелпер envelope encryption на KMS и утекающий лог — предскажите провал и выберите фикс с наибольшим рычагом.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на senior-высоте — в орбите
◷ 14 min

Провалы с секретами диагностируются в диффах, конфигах и логах. Прочтите каждый сниппет, предскажите, что утекает или ломается, затем выберите фикс, который senior-инженер сделал бы первым, — до того как тянуться к флагу настройки.

Цель

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

Сниппет 1 — закоммиченный .env

# config/.env  — отслеживается в git, в прошлый вторник запушен в публичное зеркало
DATABASE_URL=postgres://app:Sup3rSecret@db.prod.internal:5432/main
STRIPE_SECRET_KEY=sk_live_51HxQ...redacted...9aZ
JWT_SIGNING_KEY=hs256-7f3e9c1b2a8d4e6f
Викторина

Этот .env закоммитили и запушили в публичное зеркало. Вы добавляете его в .gitignore и удаляете. Какое утверждение верно?

Сниппет 2 — выборка динамической креды из Vault

// Получить короткоживущую креду БД из движка database в Vault.
secret, err := client.Logical().Read("database/creds/reporting-ro")
if err != nil {
    return err
}
user := secret.Data["username"].(string)
pass := secret.Data["password"].(string)
// leaseDuration — секунды до авто-отзыва этой креды в Vault
lease := time.Duration(secret.LeaseDuration) * time.Second

db := openDB(user, pass)
defer db.Close()
// ... долгоживущий воркер использует db часами ...
Викторина

Роль выпускает креду с часовым lease, но этот воркер работает часами. В чём дефект и фикс?

Сниппет 3 — хелпер envelope encryption на KMS

def encrypt_blob(kms, key_id: str, plaintext: bytes) -> dict:
    # просим KMS data key: открытый для использования сейчас + обёрнутый для хранения
    resp = kms.generate_data_key(KeyId=key_id, KeySpec="AES_256")
    data_key = resp["Plaintext"]
    wrapped_key = resp["CiphertextBlob"]

    ciphertext = aes_gcm_encrypt(data_key, plaintext)   # шифруем ЛОКАЛЬНО

    return {
        "ciphertext": ciphertext,
        "data_key": data_key,        # хранится рядом с шифротекстом
        "wrapped_key": wrapped_key,
    }
Викторина

Этот хелпер делает локальное AES-GCM шифрование data key, выданным KMS, — envelope encryption. Что разрушает всю схему?

Сниппет 4 — утекающий лог

app.post("/charge", async (req, res) => {
  const cfg = { apiKey: process.env.STRIPE_SECRET_KEY, amount: req.body.amount };
  try {
    const charge = await stripe.charges.create(cfg);
    res.json({ id: charge.id });
  } catch (err) {
    // вывалим всё, что есть, чтобы помочь дебагу
    console.error("charge failed", { cfg, err, body: req.body });
    res.status(500).json({ error: "charge failed" });
  }
});
Викторина

Сканер помечает этот хендлер. Где секрет покидает границу доверия и в чём фикс?

Итог

Каждый инцидент с секретами читается в артефактах: закоммиченный .env означает, что все три значения утекли и их надо ротировать, а не gitignore-ить; динамическая креда, чей lease никогда не продлевается, истекает посреди работы — продлевайте или перезапрашивайте; envelope encryption разрушается в момент, когда вы сохраняете открытый data key рядом с шифротекстом — храните только обёрнутый ключ и распаковывайте через KMS; а объект с секретом в строке лога отправляет ваш живой ключ в каждый агрегатор, поэтому редактируйте и ротируйте. Прочтите артефакт, найдите, где значение покидает границу или где неверно время жизни, и почините границу до того, как тронуть флаг.

Продолжить восхождение ↑Управление секретами: подъём по лестнице зрелости
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources2
expand
  1. 01
  2. 02

Trademarks belong to their respective owners. Editorial reference only.