Задача прилетела одной строкой: полсотни с лишним AWS Lambda-функций на Python 3.8, и до end of life рантайма оставались месяцы. На бумаге обновление рантайма Python 3.8, у которого заканчивается поддержка, — это просто смена версии. На деле, как только AWS перестаёт патчить устаревший рантайм, каждая незакрытая уязвимость становится твоей личной. К этим функциям никто не прикасался больше года. Вся коллективная мудрость умещалась в три слова: «Работает — не трогай».

Знаменитые последние слова.

Вскрываем капсулы времени

Я начал там, где начинается любой честный аудит, — с CloudWatch. Частота вызовов, error rate, даты последних изменений. Всё, что не срабатывало 90 дней, отправлялось в список кандидатов на удаление: самая быстрая миграция — это функция, которую ты удалил. Потом я открыл тех, кто выжил.

Это было не обновление Python. Это была археология. Каждая функция — маленькая капсула времени с надписью «написал в полночь и больше не возвращался». Вот что было внутри:

  • Захардкоженные креды — даже не переменные окружения, а сырые строки прямо в коде. В одной лежали доступы к базе аж с 2019 года.
  • Устаревшие библиотеки с известными CVE, не запиненные ни к чему.
  • Ноль тестов на все пятьдесят с лишним функций. Не жиденький сьют. Ноль.
  • IAM-роли с Action: "*", Resource: "*" — нараспашку, все до единой.
  • Функции, ходящие в RDS через открытый интернет, без всякой VPC-изоляции.
  • Документация, равная имени функции. И всё.

Почему не «большой взрыв»

Соблазн — переписать всё разом, щёлкнуть рубильником и молиться. Этот фильм я уже видел. Поэтому пошёл по одной функции за раз.

Каждая получала один и тот же набор процедур: рантайм с 3.8 на 3.11, каждая зависимость запинена и проверена на известные CVE, а общие библиотеки вынесены в Lambda layers — чтобы следующее обновление делалось в одном месте, а не в пятидесяти. Потом я писал тесты — для большинства это были первые тесты в их жизни — и документацию, которая объясняла, зачем функция существует, а не только что она делает. Именно «зачем» и нужно следующему инженеру в три часа ночи.

Раскатка — canary-деплой со сдвигом трафика: 5 процентов, потом 25, потом полный переход, с автоматическим откатом, если подскакивал error rate. Никакого большого взрыва. Никаких молитв. Если функция косячила на 5 процентах трафика, до остальных 95 она не доходила.

Security hardening тем же заходом

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

  • IAM переписан с нуля по принципу least privilege. Никаких wildcard. Каждая роль получила ровно те права, что функция использует, и ни одним больше.
  • Захардкоженные креды переехали в Secrets Manager, с ротацией и подтягиванием в рантайме.
  • Функции с доступом к базе заведены в VPC с приватными сабнетами — и RDS перестал торчать в открытый интернет.

Результат

Пятьдесят с лишним функций спустя:

  • Каждая функция на поддерживаемом рантайме.
  • Ноль даунтайма за всю миграцию.
  • Ноль wildcard-политик в IAM.
  • Ноль захардкоженных секретов.
  • Реальные тесты. Документация, за которую следующий инженер меня не проклянёт.

И небольшой бонус, которого я не ждал: cold start'ы уменьшились, потому что Python 3.11 просто быстрее 3.8. Скучная рутинная задача тихо сделала платформу шустрее.

«Не трогай» — это страх, а не стратегия

Вот что забывают любители serverless. «Serverless» не значит «без обслуживания» — это значит, что обслуживание невидимо, пока рантайм не доходит до end of life и всё не отваливается. Сервера, на который можно ткнуть пальцем, нет, поэтому долг прячется ещё лучше.

«Не трогай» — это технический долг на языке страха. Каждый день, что ты игнорируешь рантайм на end of life, набегают проценты — пока не приходят к оплате в виде инцидента с безопасностью или пейджа в три ночи. Каждая система «не трогай» в твоём стеке — это будущий алерт, который тебя разбудит.

Так что выбери одну на этой неделе. Самую старую, самую страшную, ту, которую лучше не трогать. Открой. Прочитай. Прогони тесты. Либо окажется, что всё в порядке, и будешь спать спокойнее, либо найдёшь креды из 2019-го раньше, чем их найдёт атакующий.

Какая система в твоём стеке самая старая и нетронутая прямо сейчас?