Два вопроса возникают у любого сервиса, как только он выходит за пределы «работает на моём ноутбуке»: где хранить секреты (пароли к базе, ключи, токены) и как понять, что происходит внутри, когда что-то идёт не так. Первое — про безопасность, второе — про наблюдаемость. В GCP под каждую задачу есть сервис. Доступ ко всем ним выдаётся через Cloud IAM.

сервисный аккаунт приложение токен из метаданных Secret Manager версии, права на секрет Cloud KMS ваш ключ, который можно отозвать Cloud Logging структурированные записи, платно за объём Cloud Monitoring метрики и оповещения

Секреты и наблюдаемость закрывают четыре сервиса, и ко всем приложение ходит по сервисному аккаунту. Из записей журнала делают метрики, из метрик оповещения, а связывает всё идентификатор трассы в каждой записи.

Обязательно

Secret Manager

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

Зачем так, а не «положить пароль в переменную окружения и забыть»:

  • секрет в одном месте, а не размазан по десяти конфигам и репозиториям;
  • доступ к нему выдаётся ролями IAM: отобрать право читать пароль так же просто, как выдать;
  • секреты версионируются: новую версию заводят рядом со старой, переключаются на неё и при беде откатываются — не переклеивая пароль по всем сервисам руками.

Две вещи Secret Manager не делает, хотя от него их обычно ждут.

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

Вторая — по умолчанию не видно, кто читал секрет. Чтения попадают в журналы доступа к данным (Data Access audit logs), а они в GCP выключены и включаются отдельно. Хотите знать, кто и когда взял пароль, — включайте их заранее, а не в день разбора инцидента.

Правило новичку: любой пароль или ключ, попавший в git, считается скомпрометированным. Даже если удалить его следующим коммитом — он останется в истории. Secret Manager снимает соблазн «просто захардкодить».

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

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

При старте. Значение читается один раз и живёт в памяти. Самый дешёвый способ (одно обращение на запуск) и правильный для пароля базы: пул соединений всё равно создаётся один раз. Цена: смена секрета не доезжает без перезапуска.

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

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

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

Отсюда рабочая схема смены пароля базы: добавить новую версию секрета → у базы одновременно действуют два пароля (или две учётные записи) → выкатить приложение, которое читает новую версию → отключить прежний пароль → отключить старую версию секрета. Тогда простоя нет вовсе, а «читается при старте» перестаёт быть проблемой.

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

Cloud KMS

Диск и так шифруется, но ключом Google, а аудитор требует, чтобы ключ был ваш и его можно было отозвать. Этим занимается Cloud KMS (Key Management Service). Тут важно не смешать два разных вопроса. Шифруются ли ваши данные в облаке — да, всегда: всё хранимое Google шифрует своими ключами по умолчанию, включать ничего не нужно. KMS отвечает на другой вопрос — чей это ключ. Он позволяет завести собственный ключ и шифровать им диски, бакеты, базы (такую схему называют CMEK): ключ лежит в KMS, доступ к нему — отдельное право IAM, и, отобрав это право, вы отрезаете доступ к данным независимо от прав на сами данные. Берут это, когда так требует регламент или когда нужно уметь «выключить» данные одним движением.

Cloud Logging и Cloud Monitoring

Эти сервисы (исторически известные как Stackdriver, теперь Cloud Operations) закрывают наблюдаемость.

Cloud Logging собирает логи со всех ресурсов в одно место, где их можно искать и фильтровать. Управляемые платформы — Cloud Run, Cloud Functions, GKE — пишут туда сами: всё, что сервис вывел в стандартный поток, оказывается в Logging. А вот на обычной виртуальной машине Compute Engine само ничего не поедет: пока на неё не поставлен агент (Ops Agent), логи вашего приложения остаются лежать на диске машины, и в консоли их не будет. Обычно об этом узнают в тот момент, когда ищут логи упавшего запроса. Практический совет: пишите логи структурированно (с полями — уровень, идентификатор запроса, сервис), а не сплошным текстом — по структурированным логам можно искать и строить фильтры.

Cloud Monitoring показывает картину во времени — метрики (загрузку процессора, задержку, число ошибок), из которых собирают дашборды и алерты — правила вида «если ошибок больше стольки-то за минуту — разбудить дежурного». А Cloud Trace показывает, как запрос проходит сквозь сервисы, и где именно тормозит.

Ключевая мысль для новичка: наблюдаемость нужна до аварии, а не после. Метрики и алерты, настроенные заранее, превращают «пользователи жалуются, а мы не понимаем почему» в «нам пришло уведомление, и мы уже чиним». Общие правила логирования не зависят от облака — их разбирает Observability style guide.

Audit Logs и Security Command Center

Cloud Audit Logs пишет журнал действий — только это не один журнал, а два разных, и разницу между ними лучше знать до инцидента, а не после:

  • Admin Activity — кто создал, изменил или удалил ресурс, кто поменял права. Включён всегда, выключить его нельзя, платить за него не надо. Это он отвечает на вопрос «откуда взялся этот публичный бакет?»;
  • Data Access — кто читал и писал сами данные: скачал объект из бакета, прочитал секрет, сходил в базу. По умолчанию выключен (исключение — BigQuery), включается адресно по сервисам, и за объём этих логов вы платите.

Отсюда практический вывод: на вопрос «кто трогал инфраструктуру» журнал ответит всегда, а на вопрос «кто унёс данные» — только если вы включили вторую половину заранее.

Security Command Center оценивает состояние безопасности: находит открытые наружу ресурсы, слабые настройки, уязвимости и подсказывает, что исправить.

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

Эта связка — секреты в Secret Manager, шифрование на KMS, логи в Cloud Logging, метрики и алерты в Cloud Monitoring — базовый гигиенический минимум любого боевого сервиса. Без неё сервис вроде бы работает, но при первой же проблеме вы оказываетесь слепы.

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

  • хранят пароли в коде или конфигах вместо Secret Manager;
  • логируют бессистемно — сплошным текстом, без идентификатора запроса, и потом ничего не находят;
  • настраивают наблюдаемость после первой аварии, а не до неё;
  • логируют секреты и персональные данные — и утечка переезжает в логи.
Дополнительно: при первом чтении можно пропустить

Глубже: журналы стоят денеграсширенное

Самая частая неожиданность в счёте за наблюдаемость, и она устроена так.

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

Срок хранения по умолчанию у основного журнала — 30 дней; у журнала административного аудита он дольше (около 400 дней) и не тарифицируется. То есть обычные логи приложения живут месяц, если не настроить иначе.

Что раздувает объём: отладочный уровень в боевом контуре, журналирование тел запросов, подробные журналы платформы (записи о сетевых потоках, журналы правил фильтрации, журналы доступа к данным), и журналы кластера Kubernetes, если включить в них всё.

Три рычага, которые сокращают счёт в разы:

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

gcloud logging sinks update _Default --add-exclusion=name=drop-health,\
filter='resource.type="cloud_run_revision" AND httpRequest.requestUrl:"/health"'

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

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

И то, что стоит сделать в первый же день: посмотреть, сколько вы принимаете. В отчёте по затратам это отдельная позиция, а в самом сервисе есть панель с разбивкой объёма по источникам — обычно выясняется, что 80 % объёма даёт один-два источника.

Глубже: метрики на основе логов: мостик к оповещениямрасширенное

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

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

gcloud logging metrics create payment_failures \
  --description="Отказы платежей" \
  --log-filter='resource.type="cloud_run_revision" AND jsonPayload.event="payment_failed"'

Дальше на эту метрику ставят правило: «больше десяти за пять минут — оповестить». То есть путь от «мы это логируем» до «нас об этом предупредят» оказывается коротким и не требует отдельной системы метрик.

Два вида таких метрик. Счётчик — сколько записей подошло под фильтр (отказы, исключения, определённые события). Распределение — числовое значение, извлечённое из записи (длительность операции, размер пачки): по нему считаются процентили.

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

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

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

Про трассировку сказано одним предложением, и ей нужны две детали.

Не все запросы отслеживаются. Собирать трассы для каждого запроса дорого и не нужно: обычно берут выборку — долю запросов (проценты) плюс все запросы с ошибками и все медленные. Настраивается это в библиотеке трассировки; значение по умолчанию у части библиотек очень низкое (десятые доли процента), и это первое, что стоит проверить, если «трассы почему-то пустые».

Трассировка требует сквозного идентификатора. Он передаётся заголовком между сервисами: в GCP это исторически X-Cloud-Trace-Context, в стандарте OpenTelemetry — traceparent. Библиотека читает его на входе и добавляет к исходящим вызовам; если хоть один сервис в цепочке этого не делает, трасса обрывается.

И главная связка, ради которой всё это: идентификатор трассы попадает в записи журнала. Тогда запрос из журнала открывается как трасса, а трасса — как набор записей. В структурированной записи для этого есть специальное поле (logging.googleapis.com/trace), и библиотеки заполняют его сами, если трассировка подключена.

Практический минимум: подключить трассировку с выборкой 5–10 % плюс все ошибки, убедиться, что идентификатор попадает в журнал, и возвращать его клиенту в заголовке ответа — тогда обращение пользователя превращается в готовую точку входа для разбора.

Глубже: чего не логироватьрасширенное

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

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

Что пишут вместо: идентификаторы (customerId, orderId), маскированные значения для диагностики (u***@example.com) одной общей функцией, шаблон адреса запроса (GET /api/customers/{id}) вместо фактической строки с параметрами.

И тот же канал — метрики и трассы. Метка метрики с адресом электронной почты — это и утечка, и взрыв числа временных рядов; атрибут спана с персональными данными уезжает в то же хранилище. Правило одно: идентификаторы, а не данные.

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

Коротко

  • Secret Manager хранит секреты с версиями и правами IAM, но пароль за вас не меняет: расписание ротации это напоминание в Pub/Sub, а чтения видны только с включёнными журналами доступа к данным.
  • Секрет берут при старте, при каждом обращении или с кэшем на минуты; новая версия доезжает при следующем чтении, пароль базы меняют с двумя действующими, версии отключают, а не удаляют.
  • Cloud KMS отвечает на вопрос «чей ключ и можно ли его отозвать», а шифрование диска и так есть, только ключом Google.
  • Cloud Logging собирает логи управляемых платформ сам, Cloud Monitoring строит графики и оповещения; наблюдаемость настраивают до аварии.
  • Журналы платные сверх 50 ГБ в месяц и хранятся 30 дней: исключения отбрасывают шум до приёма, отводы уводят долгое в дешёвое хранилище, сроки хранения ставят по журналам.
  • Метрики на основе логов превращают записи в числа для оповещений: счётчик или распределение, без меток с высокой мощностью.
  • Трассировку собирают выборкой 5–10 % плюс ошибки, идентификатор трассы кладут в записи журнала и возвращают клиенту.
  • В логи, метрики и трассы не пишут персональные данные и секреты: идентификаторы, маскирование одной функцией, шаблон адреса вместо адреса.
  • Admin Activity пишется всегда и бесплатно, Data Access выключен по умолчанию и включается адресно; Security Command Center находит открытые наружу ресурсы.

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