Когда приложение работает на вашем ноутбуке, пароль от базы можно просто положить в файл рядом с кодом. В облаке так нельзя: код видят коллеги, файлы попадают в систему контроля версий, серверов много и они появляются и исчезают сами. Поэтому в AWS есть отдельные сервисы для двух задач, которые раньше решались «как-нибудь»: где безопасно хранить секреты и как понимать, что вообще происходит внутри ваших серверов.

Эта статья — про четыре таких сервиса. Secrets Manager и SSM Parameter Store хранят пароли и настройки. KMS отвечает за шифрование. CloudWatch собирает логи, метрики и присылает оповещения, когда что-то пошло не так. Рядом разберём и CloudTrail — сопутствующий инструмент аудита, который фиксирует, кто и что делал в аккаунте. Пройдёмся по каждому по очереди, человеческим языком и с примерами команд, которые можно попробовать самому.

роль сервиса приложение права на чтение Secrets Manager пароль базы, ротация Parameter Store адреса и флаги, бесплатно KMS ключи, которые не покидают сервис CloudWatch логи, метрики, сигналы

Четыре сервиса закрывают два вопроса: где живёт то, что нельзя показывать, и как узнать, что сервису плохо. Доступ ко всем четырём даёт роль сервиса, а не ключи в конфиге.

Обязательно

Secrets Manager: сейф для паролей

Секрет — это любая чувствительная строка: пароль от базы данных, ключ к стороннему API, токен. Secrets Manager — это управляемое хранилище таких строк. Вы кладёте секрет один раз, а приложение запрашивает его при старте по имени.

Главное, что вы получаете взамен пары строк в файле:

  • Шифрование — секрет хранится зашифрованным, в открытом виде его нет нигде на диске.
  • Версии — при смене пароля старое значение не теряется, можно откатиться.
  • Аудит — каждое чтение секрета фиксируется, видно кто и когда обращался.
  • Автоматическая ротация — Secrets Manager умеет сам менять пароль базы по расписанию.

Положить секрет и прочитать его — две команды:

aws secretsmanager create-secret --name prod/db/password --secret-string "s3cr3t-value"
aws secretsmanager get-secret-value --secret-id prod/db/password --query SecretString --output text

Ротация устроена интереснее, чем кажется. Когда вы её включаете для базы RDS, AWS заводит маленькую функцию (Lambda), которая по расписанию проходит четыре шага: создаёт новый пароль, прописывает его в базу, проверяет вход с новым паролем и только потом делает его текущим.

Дальше всё зависит от выбранной стратегии, и вот тут важно не обмануться. По умолчанию берут одного пользователя: пароль меняется у него же, и между моментом, когда пароль поменялся в базе, и моментом, когда обновился секрет, есть короткий промежуток — приложение со старым значением в руках получит отказ. Уже открытые соединения при этом не рвутся, а лечится это повтором запроса. Если простой недопустим совсем, выбирают двух чередующихся пользователей: Secrets Manager заводит копию пользователя и меняет им пароли по очереди, так что действующие учётные данные есть всегда — вот это и есть смена пароля без простоя.

Кто имеет право читать секрет? Не человек, а роль сервиса — об IAM-ролях подробно в статье про основы AWS. В итоге пароля нет ни в коде, ни в системе контроля версий, ни в переменных сборки — только в Secrets Manager. Это закрывает целый класс утечек: украсть нечего, потому что в репозитории секрета просто нет.

Когда приложение читает секрет

Остаётся практический вопрос: в какой момент приложение обращается к хранилищу — и от ответа зависит, работает ли обещанная смена пароля без простоя.

При старте, один раз. Так делает подключение секретов как свойств приложения: значения читаются на запуске и живут в памяти. Это правильный вариант для пароля базы (пул соединений всё равно создаётся один раз) и самый дешёвый — одно обращение на запуск. Цена: смена секрета не подхватывается без перезапуска, и именно поэтому ротация делается с двумя действующими значениями.

При каждом обращении. Честно свежее значение, но каждое чтение — платный запрос к хранилищу (порядка 5 центов за 10 тысяч запросов) и лишние миллисекунды к каждому вызову. Для ключа, который используется в каждом запросе, это заметно и в счёте, и в задержке.

С кэшированием на несколько минут — золотая середина, и для этого есть готовый слой: у AWS есть отдельная библиотека кэширования секретов, которая держит значение в памяти и сама обновляет его по истечении срока. Тогда смена секрета доезжает до приложения за минуты, без перезапуска, а число обращений остаётся небольшим.

Как это укладывается в схему ротации. Для базы: два чередующихся пользователя плюс чтение при старте — простоя нет, потому что действующие данные есть всегда. Для внешнего ключа к чужому API: кэш на пять минут — смена ключа доезжает сама. Для чего-то, что обязано смениться мгновенно: чтение при каждом обращении и осознанная плата за это. Разбор того, как это выглядит в коде приложения, — в статье про подключение SDK.

SSM Parameter Store: настройки и дешёвые секреты

SSM Parameter Store (часть сервиса AWS Systems Manager) — это хранилище для настроек приложения: адреса других сервисов, признаки включённых функций, имена бакетов. Параметры бывают двух типов: обычная строка (String) и зашифрованная (SecureString). SecureString шифруется через KMS — то есть Parameter Store тоже умеет хранить секреты.

aws ssm put-parameter --name /prod/app/feature-x --type String --value enabled
aws ssm put-parameter --name /prod/db/password --type SecureString --value "s3cr3t-value"
aws ssm get-parameter --name /prod/db/password --with-decryption --query Parameter.Value --output text

Зачем тогда два сервиса? Разница простая и в основном про деньги и удобство. Стандартный уровень Parameter Store бесплатный — ни за хранение, ни за обращения платить не нужно. Secrets Manager стоит около 0,40 доллара за секрет в месяц плюс копейки за обращения, но даёт то, чего у Parameter Store нет: автоматическую ротацию паролей и готовую интеграцию с базами.

Практическое правило новичка:

  • нужна автоматическая смена пароля базы — Secrets Manager;
  • просто настройки или редкий секрет без ротации, и хочется не платить — SSM Parameter Store с типом SecureString.

И ещё одна аналогия для границы между секретом и настройкой: стыдно было бы увидеть это значение в логе — значит, это секрет, и шифруем. Не стыдно (адрес сервиса, флаг) — обычный параметр.

KMS: где живут ключи шифрования

Любое шифрование держится на ключе. Если ключ лежит рядом с зашифрованными данными — толку от шифрования мало. KMS (Key Management Service) решает эту проблему: ключи хранятся внутри защищённого оборудования AWS и никогда его не покидают. Вы не получаете сам ключ — вы просите KMS зашифровать или расшифровать что-то этим ключом.

Для новичка KMS чаще всего выглядит как «галочка, которую нельзя забыть». При создании диска, бакета S3, базы RDS или очереди есть опция «шифровать при хранении» (encrypt at rest) — и она использует именно KMS. Современный подход простой: шифруем всё.

Ключи бывают трёх видов:

  • AWS owned — ключи самого сервиса AWS, они лежат вне вашего аккаунта. Именно ими по умолчанию шифруют данные многие сервисы: вы их не видите, не настраиваете, не платите за них и в аудите их не найдёте.
  • AWS managed — ключ создан за вас, но лежит в вашем аккаунте, и его использование видно в аудите. Подходит для большинства данных.
  • Customer managed — вы сами заводите ключ, можете его отозвать и полностью управляете доступом к нему. Берут для особо чувствительных данных. Это единственный вид, за который приходит отдельный счёт: около доллара в месяц за ключ плюс копейки за обращения.

Иногда KMS появляется прямо в коде — это приём под названием envelope encryption («шифрование конвертом»). Данные шифруются обычным ключом данных, а сам этот ключ — мастер-ключом в KMS. Аналогия: вы кладёте письмо в конверт с замком (ключ данных), а ключ от конверта запираете в банковском сейфе (KMS). Нужно это редко, и когда нужно — берут готовую библиотеку (AWS Encryption SDK), а не пишут криптографию сами: самодельное шифрование почти всегда содержит ошибки.

CloudTrail: кто что сделал в аккаунте

CloudTrail записывает управляющие действия в аккаунте AWS: кто, что, когда и откуда вызвал — создал машину, поменял политику, удалил очередь. Это не инструмент только для безопасников — это ваш способ разобраться, когда что-то сломалось. «Кто удалил очередь?», «когда поменяли настройку базы?», «какая роль читала секрет?» — ответ находится за минуты.

Два уточнения, без которых на CloudTrail надеются зря. Первое: «каждое действие» — это про управление. События уровня данных (чтение и запись отдельных объектов в хранилище, вызовы функций) по умолчанию не пишутся вовсе, их включают отдельно и платят за объём. Второе: само собой у вас есть только история событий за последние 90 дней — её никто не настраивает, она просто доступна. А постоянный журнал (trail) с выгрузкой в бакет надо завести самому, иначе через три месяца следы исчезнут, и разбирать происшествие будет уже не по чему.

CloudWatch: логи, метрики и оповещения

Сервис тормозит, и непонятно, база это или приложение. Ответ ищут в трёх местах, и все три живут в CloudWatch — родной системе наблюдения AWS: в Logs лежат текстовые логи приложений и сервисов, в Metrics — числа во времени (загрузка процессора базы, длина очереди, число запросов), а Alarms — правила вида «если метрика превысила порог — пришли оповещение», чтобы узнавать о проблеме раньше пользователей.

Большой плюс для начинающего: метрики управляемых сервисов появляются в CloudWatch сами, без настройки. Создали базу RDS — её загрузка процессора и число соединений уже видны. Дальше на любую метрику вешается аларм:

aws cloudwatch put-metric-alarm \
  --alarm-name rds-cpu-high \
  --namespace AWS/RDS \
  --metric-name CPUUtilization \
  --statistic Average \
  --period 300 \
  --threshold 80 \
  --comparison-operator GreaterThanThreshold \
  --evaluation-periods 2 \
  --alarm-actions arn:aws:sns:eu-central-1:111122223333:ops-alerts

Последняя строка — не украшение. Сам аларм никому не пишет: он умеет только дёрнуть тему SNS, а уже она рассылает письма, сообщения или дёргает вашу функцию. Без --alarm-actions аларм честно переключится в состояние ALARM — и об этом не узнает никто.

Логи приложения можно отправлять в CloudWatch и искать по ним. Полезный совет на старте: пишите логи структурированно (в формате JSON, а не сплошным текстом) — тогда по ним удобно фильтровать и строить метрики. Минимум полезных полей — уровень (error/info), сообщение и идентификатор запроса, по которому можно связать строки одного обращения.

Одна важная деталь про счета: в CloudWatch вы платите за объём логов и за собственные метрики. Если логировать каждую мелочь или заводить метрику на каждый уникальный параметр — счёт быстро растёт. Но главная причина неприятного счёта другая, и о ней не догадываются: у группы логов срок хранения по умолчанию — «никогда не удалять». То есть за отладочные логи двухлетней давности вы платите до сих пор. Одна настройка (retention, скажем, 30 дней на приложение) закрывает бо́льшую часть проблемы.

Многие команды используют CloudWatch вместе со своими инструментами наблюдения (например, Grafana): метрики приложения и трассировки запросов хранят у себя, а метрики управляемых сервисов забирают из CloudWatch в общую панель. Так получается один экран на всё с двумя источниками данных — частая зрелая схема.

Трассировка: третий столп

В CloudWatch есть логи и метрики, а третьего классического инструмента наблюдаемости — трассировки — там нет: это отдельный сервис.

X-Ray собирает путь одного запроса через все звенья: шлюз, функция, база, соседний сервис. В результате получается картинка со временем каждого шага и ответ на вопрос «где ушли 800 миллисекунд из 900». Включается он двумя вещами: разрешением в настройках сервиса (у функции — одна галочка, у контейнера — агент рядом) и библиотекой в приложении, которая проставляет заголовки трассировки и размечает вызовы.

OpenTelemetry — открытый стандарт, который делает то же самое и не привязан к облаку: тот же код собирает трассы, а отправлять их можно и в X-Ray (через сборщик AWS Distro for OpenTelemetry), и в свой стек. Для команды, у которой уже есть свой сбор трасс, это правильный путь: ничего переписывать при переезде не придётся.

Что даёт трассировка помимо картинки: карту зависимостей сервиса (кто кого зовёт — строится сама по трассам), распределение задержек по шагам и связь логов с трассой по идентификатору. Последнее и есть переход от «у нас есть логи» к наблюдаемости: в записи лога лежит идентификатор трассы, по нему открывается путь запроса целиком.

Как связать записи одного запроса

Совет «пишите структурированно» стоит довести до конкретных полей, потому что связывание записей — это половина пользы от логов.

В каждой записи должно быть три идентификатора:

  • traceId — идентификатор всего пути запроса через систему. Приходит извне в заголовке (X-Amzn-Trace-Id у сервисов AWS, traceparent у OpenTelemetry) или создаётся на входе, если запрос пришёл снаружи.
  • spanId — идентификатор конкретного шага внутри трассы; нужен, чтобы сопоставить запись с точкой на диаграмме.
  • requestId — идентификатор обращения к вашему сервису; у функций он есть сам (AWS Request ID и он же в отчёте), у сервиса за шлюзом его выдаёт шлюз.

Как это попадает в лог на практике: библиотека трассировки кладёт идентификаторы в контекст потока (в терминах журналирования — в диагностический контекст), а формат вывода логов включает их в каждую строку. Настраивается один раз и дальше работает само.

Что это даёт: запрос, на который жалуется пользователь, находится по идентификатору из ответа (его полезно возвращать в заголовке), а дальше одним фильтром собираются все записи этого запроса — из шлюза, из приложения, из фоновой обработки. Без этих полей разбор инцидента превращается в сопоставление времени, а при десятке параллельных запросов в секунду это уже невозможно.

Где это применяется

Эти четыре сервиса встречаются в любом облачном проекте, как только он выходит за пределы «запустил у себя на ноутбуке». Secrets Manager и SSM прячут пароли при работе с базами из статьи про управляемые данные и DynamoDB; шифрование KMS включают для S3 и объектного хранилища; CloudWatch ставят рядом с масштабированием и доступностью и бессерверными функциями, чтобы видеть нагрузку. Когда вы описываете инфраструктуру кодом — через Terraform, CloudFormation или CDK — секреты, ключи и алармы тоже задаются там, а сборочные конвейеры из раздела про CI/CD читают секреты из этих хранилищ, а не из своих переменных.

Типичные ошибки новичков:

  • Секрет в коде или в системе контроля версий. Самая частая утечка. Пароль всегда живёт в Secrets Manager или SSM, в репозитории — только имя секрета.
  • Слишком широкие права у роли. Роль сервиса должна читать только свои секреты и свои бакеты — это принцип наименьших привилегий, про роли см. основы AWS и IAM.
  • Шифрование забыли включить. Лишняя галочка кажется ненужной ровно до первого аудита. Включайте шифрование сразу при создании ресурса.
  • Нет алармов, узнаём о проблеме от пользователей. Хотя бы пара алармов на загрузку базы и на ошибки приложения экономят много нервов.
  • Логи валятся сплошным текстом, и счёт за CloudWatch неожиданно большой. Структурируйте логи и не пишите лишнего.
Дополнительно: при первом чтении можно пропустить

Глубже: как искать по логам: Logs Insightsрасширенное

«Отправляйте логи в CloudWatch и ищите по ним» требует продолжения: чем именно искать. Обычный просмотр группы логов годится, пока записей сотни; дальше пользуются отдельным инструментом — CloudWatch Logs Insights, это язык запросов по логам.

fields @timestamp, level, message, requestId, durationMs
| filter level = "ERROR"
| filter durationMs > 1000
| sort @timestamp desc
| limit 50

Что он умеет, кроме фильтров: считать (stats count() by errorCode), группировать по времени (stats avg(durationMs) by bin(5m)), разбирать неструктурированные строки (parse) и строить по результату график. Структурированные логи в формате JSON здесь и окупаются: поля становятся полями запроса сами, без разбора текста.

Два практических приёма. Первый — разбор инцидента по идентификатору запроса: filter requestId = "abc-123" собирает все строки одного обращения, в том числе из разных сервисов, если идентификатор пробрасывается. Второй — быстрая сводка: stats count() by level за последний час сразу показывает, выросло ли число ошибок, без всяких панелей.

Оплата — за объём просканированных данных, поэтому запросы всегда ограничивают периодом и, по возможности, конкретной группой логов. И одна настройка, которая экономит и время, и деньги: сроки хранения (retention) по группам логов, о которых ниже.

Глубже: метрики: пять минут по умолчаниюрасширенное

Деталь, из-за которой сигналы срабатывают позже, чем ожидают. Базовые метрики управляемых сервисов и виртуальных машин собираются раз в пять минут. Именно поэтому в примере сигнала выше стоит период 300 секунд: меньше ставить бессмысленно, точек просто не будет.

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

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

И про свои метрики: у собственных метрик плата идёт за каждую уникальную комбинацию имени и измерений. Метрика с идентификатором пользователя в измерениях — это отдельная метрика на каждого пользователя и счёт, который замечают через месяц; в измерениях держат только значения из короткого списка. Дешевле и правильнее публиковать метрики через встроенный формат в логах (Embedded Metric Format) — тогда числа извлекаются из строк лога, и платите вы за объём логов, а не за каждую метрику отдельно.

Глубже: безопасность, которой не виднорасширенное

Секреты и шифрование — только часть безопасности. Ещё четыре вещи включают один раз на аккаунт, и они работают сами.

Запрет публичного доступа к хранилищу объектов. Настройка уровня аккаунта (Block Public Access) не даёт сделать бакет публичным, даже если кто-то попытается это настроить руками. Включается раз и снимает самый частый источник новостей об утечках.

GuardDuty — обнаружение угроз по журналам: он читает журнал вызовов API, журналы сетевых потоков и обращения к DNS и ищет подозрительное — вход из необычной страны, обращение к известным адресам злоумышленников, перебор, попытку майнинга на ваших машинах. Включается галочкой на аккаунт (и на всю организацию сразу), находки складывает в общий список и платится по объёму анализируемых журналов.

AWS Config — запись состояния и правил соответствия: он помнит, как выглядел каждый ресурс во времени (удобно при разборе «кто это поменял»), и умеет проверять правила вида «у всех томов включено шифрование», «нет групп безопасности с открытым доступом на порт базы». Нарушение правила превращается в находку, а иногда и в автоматическое исправление.

Security Hub — сводная панель поверх остальных: собирает находки GuardDuty, Config, сканирования образов и своих проверок в один список с приоритетами и умеет прогонять готовые наборы требований (например, базовый набор AWS или отраслевые стандарты).

Порядок включения для новой организации, если начинать с нуля: запрет публичного доступа к хранилищу, журнал вызовов API на всю организацию (он у вас уже есть по умолчанию, но не хранится долго), GuardDuty, потом Config с десятком правил, и только потом сводную панель — иначе она сразу выдаст двести находок, и разбирать их никто не станет.

Глубже: логи дешевле: сроки, выгрузка, свой стекрасширенное

Плата за логи растёт незаметно, и есть три рычага, которые её сокращают в разы.

Срок хранения. У группы логов по умолчанию он бесконечный. Первое, что делают в аккаунте, — ставят разумные сроки: 7–14 дней на отладочные логи стендов, 30 дней на логи приложений, дольше — только там, где это требование регулятора. Правило retention на группу настраивается одной командой и применяется сразу.

Выгрузка в хранилище объектов. Хранение в системе логов стоит дороже хранения объектов в разы. Схема такая: горячий срок (недели) живёт в системе логов и доступен быстрому поиску, дальше логи экспортируются в хранилище с дешёвым классом и лежат там годами. Искать по ним медленнее (для этого есть отдельный сервис запросов по данным в хранилище), зато дешевле на порядок.

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

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

Коротко

  • Secrets Manager хранит пароли зашифрованными с версиями, аудитом и ротацией; читает секрет роль сервиса, а в репозитории живёт только имя секрета.
  • Ротация одним пользователем даёт окно между сменой пароля в базе и обновлением секрета; без простоя работают два чередующихся пользователя плюс чтение при старте, а ключ внешнего API берут с кэшем на минуты.
  • SSM Parameter Store бесплатен и годится для настроек и редких секретов типа SecureString; Secrets Manager берут ради автоматической ротации. Стыдно увидеть значение в логе, значит это секрет.
  • KMS держит ключи в защищённом оборудовании и никогда их не отдаёт: ключи AWS owned невидимы, AWS managed лежат в аккаунте, customer managed отзываете вы и платите около доллара в месяц; шифрование при хранении включают при создании ресурса.
  • CloudTrail пишет управляющие действия: кто, что и откуда; события уровня данных включают отдельно, и журнал вызовов IAM живёт в Северной Вирджинии.
  • CloudWatch собирает логи, метрики и сигналы; метрики управляемых сервисов появляются сами, а сигнал без действия на тему SNS никому не пишет. Логи пишут структурированно и платят за объём.
  • Базовые метрики идут раз в пять минут, поминутные стоят денег: сигналы «сервис лежит» строят на ошибках балансировщика и своих метриках, а измерение с идентификатором пользователя рождает метрику на каждого.
  • В каждой записи лога три идентификатора: traceId, spanId и requestId; трассировка это X-Ray или OpenTelemetry, и она отвечает, где ушли 800 миллисекунд из 900.
  • На аккаунт один раз включают запрет публичного доступа к хранилищу, GuardDuty, Config и Security Hub; логи дешевеют от сроков хранения, выгрузки в объектное хранилище и отказа от DEBUG в бою.

Что почитать дальше