SkillGridИзучай computer science на практике

Секреты: ключи, хранение и ротация

Почему ключ в git — это ключ, которым ты больше не владеешь, от чего на самом деле защищают переменные окружения, как работает ротация до и после утечки и честный подсчёт того, с чего начинаются утечки на самом деле.

15 мин · 50 XP

Прошлый урок закончился паролем. Пароли — это секреты, которые вводит человек; этот урок о секретах, которыми пользуется программа, когда никто не смотрит: ключи API, пароли к базам, ключи подписи, токены к другим сервисам. Ломаются они иначе, чем человеческие пароли. Никто не переиспользует пароль от базы из лени, никто его не забывает и никто не выбирает слабый, потому что так проще набирать. Они ломаются потому, что их копируют туда, где им никогда не следовало лежать, и потому что живут они вечно.

Секрет, закоммиченный в репозиторий, — это не файл, который можно удалить. Git хранит снимки, и каждый снимок, в котором ключ когда-либо был, содержит его до сих пор. Удаление строки в новом коммите убирает ключ из текущего состояния и ничего не меняет в истории. Даже force-push, переписывающий ветку, оставляет старые объекты достижимыми через reflog, через любой форк, через любой уже сделанный клон и какое-то время через хранилище самого провайдера. Это не изъян Git; это то, для чего существует история, адресуемая по содержимому. Практический вывод — тот, принять который командам дороже всего: к моменту, когда ты заметил, учётные данные надо считать публичными. Как найти утёкший ключ в истории и убедиться, что он всё ещё достижим. Поиск — это лёгкая часть.

$ git log --all -S 'AKIA' --oneline
9f2c1ab  remove keys from config
4d7e0f3  add deployment config

$ git show 4d7e0f3:config/prod.env | grep -c AKIA
1

$ git rev-list --all --count
8421

# the commit is still reachable: history is append-onlyКак найти утёкший ключ в истории и убедиться, что он всё ещё достижим. Поиск — это лёгкая часть.

Переменные окружения — стандартный совет, и это шаг вперёд, но их часто переоценивают. Что они действительно дают: секрет не в репозитории, не в образе контейнера и отличается между стендом и продом без правки кода. Чего они не дают: никакой изоляции вообще. В Linux окружение работающего процесса читается из /proc, поэтому ключ может прочитать любой процесс, работающий от того же пользователя. Он попадает в дампы падений и в дочерние процессы, которые ты порождаешь, — именно так ключ от платёжного сервиса всплывает в логе несвязанной задачи. А на многих платформах он виден на странице настроек в панели, то есть виден всем, у кого есть право деплоя. Переменные окружения переносят секрет из плохого места в лучшее. Они не сейф. Переменную окружения прочитает всё, что уже может работать от имени этого пользователя. Это не ничего, но это не секретность. Вывод ключа — это мост от человеческого секрета к криптографическому ключу. Пароль не используется как ключ AES напрямую, потому что пароли короткие и низкоэнтропийные, а ключи должны быть равномерно случайными. Функция вывода берёт пароль, соль и намеренно дорогой параметр стоимости и выдаёт ключ нужной длины. Та же идея встречается в трёх местах сразу, и стоит увидеть, что это одна и та же идея: вывод ключа из парольной фразы, вывод хеша пароля, устойчивого к перебору, и вывод отдельного ключа на запись из мастер-ключа, чтобы утечка одного ключа не открывала остальные. Именно параметр стоимости заставляет каждую из них сопротивляться атакующему, у которого уже есть сохранённый материал. У шифрования диска есть характерный режим отказа, который стоит назвать. Если ключ, отпирающий диск, лежит на той же машине или автоматически подтягивается при загрузке из файла конфигурации, то данные есть у любого, кто может загрузить эту машину или прочитать этот файл. Поэтому полнодисковое шифрование защищает украденный ноутбук и почти ничего не даёт для работающего сервера, до которого атакующий уже добрался.

in transit     TLS between client and service      a key you never see
at rest        disk encryption, KMS envelope      server holds the key
tokenized      provider keeps the card number    your database holds a token

PCI DSS 4.0 requires cardholder data encrypted in transit and at rest

None of the three protects against a valid account using the API.Три слоя, которые имеют в виду, когда говорят «данные зашифрованы». Они защищают от разного, и ни один не защищает от действительного запроса.
AppVaultDatabaseauthenticate as service, ask for db passwordpolicy allows this service, lease 1hshort-lived credentialconnect with that credentialnothing long-lived sits in a file or envlease expires, reconnect with a fresh one

Практика

  1. Ты обнаруживаешь, что рабочий ключ API закоммитили три месяца назад и удалили следующим коммитом. Ключ всё ещё активен. Какая первая реакция верна?

    Подсказки
    • Спрашивать, лежит ли файл до сих пор в рабочем каталоге, — не тот вопрос: коммит хранит собственную копию каждого файла, которого когда-либо касался.
    • Прежде чем что-то переписывать, реши, действительны ли ещё эти учётные данные. Если да, уборка — не срочная часть.
  2. Расставь реакцию на утечку учётных данных по порядку, от первого действия к последнему.

    1. 1выпустить замену и развести её по всем потребителям старого ключа
    2. 2переписать историю или сознательно принять, что она останется, и добавить сканирование в конвейер, чтобы следующую утечку поймать до слияния
    3. 3просмотреть логи на все случаи использования старого ключа, вплоть до момента коммита
    4. 4записать, что произошло и что поймало бы это раньше, пока детали ещё свежи
    5. 5отозвать учётные данные у провайдера, чтобы они немедленно перестали работать
    Подсказки
    • Пока утёкшие учётные данные действительны, всё остальное — украшение. Отзыв идёт первым, а не последним.
    • Чистить репозиторий имеет смысл только после того, как учётные данные больше нельзя использовать, потому что переписывание истории — дело долгое и разрушительное.
  3. Сопоставь каждое место, где может жить секрет, с тем, от чего оно действительно защищает.

    Подсказки
    • Для каждого варианта хранения спроси, кто может его прочитать: сам процесс, любой, кто может читать файловую систему, или только тот, кто прошёл аутентификацию.
    • Переменные окружения держат секреты вне репозитория, и это настоящая ценность. Но от всего, что работает на той же машине, они секрет не прячут.

Вопросы по этому уроку

Это бесплатно?

Да. Первый уровень каждого предмета бесплатный и не требует аккаунта. Дальше уровни и старшие грейды платные — именно это позволяет проекту существовать.

На какой возраст рассчитано?

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

Нужно ли уже уметь программировать?

Нет. Логика, физика и сети начинаются с нуля. Код ты пишешь в разделе языков — и он тоже начинается с самого начала.

Нужно что-то устанавливать?

Нет. Всё работает в браузере: теория, практика и интерактивные симуляции. Скачивать нечего и настраивать нечего.

Сколько времени занимает один предмет?

Урок — от 10 до 15 минут. Грейд «джун» это примерно 12–20 уроков, то есть несколько недель регулярных занятий, а не один вечер.

Обязательно идти по порядку?

Внутри грейда уровни открываются по очереди: каждый опирается на предыдущий. А между предметами ты свободен — начинай с логики, физики или сетей.