Cloudflare предоставляет услуги, которые помогают работать 20% веба, но мы делаем это не в одиночку. Разработчики на нашей платформе используют множество инструментов и сервисов от других компаний. Cloudflare предлагает богатый API для нашей платформы, который позволяет разработчикам создавать автоматизацию, CI/CD и интеграции, связывающие различные части их инфраструктуры. Ранее в этом месяце мы анонсировали самоуправляемый OAuth, упростив для клиентов создание и управление собственными OAuth-клиентами для делегированного доступа к Cloudflare API.
Cloudflare не новичок в OAuth. Если вы использовали Wrangler или интеграции от партнёров, таких как PlanetScale, то вы уже с ним сталкивались. Однако до сих пор сторонний OAuth был доступен только через небольшое количество вручную добавленных интеграций и не был доступен широкому кругу разработчиков. Это означало, что разработчикам, создающим собственные интеграции, приходилось полагаться на API-токены, которые сложнее управлять и плохо подходят для многих делегированных потоков приложений.
За последний год мы подключили растущее число ранних партнёров, одновременно улучшая модель согласия, отзыва и безопасности Cloudflare OAuth. Но по мере роста нашей платформы для разработчиков и увеличения спроса на делегированный доступ со стороны агентных инструментов стало очевидно, что открытие OAuth для всех клиентов критически важно для успеха нашей платформы.
С самоуправляемым OAuth разработчики теперь могут предлагать стандартный поток OAuth, в котором клиенты предоставляют ограниченный доступ напрямую, что упрощает создание SaaS-интеграций, внутренних платформ для разработчиков и агентных инструментов, одновременно предоставляя пользователям более понятное согласие, лёгкий отзыв и больший контроль над тем, что может делать приложение.
Масштабирование экосистемы безопасно
Хотя наше предыдущее решение OAuth было достаточным для небольшого числа тщательно управляемых партнёров, мы поняли, что наша модель разрешений, опыт согласия и способы смягчения потенциальных векторов злоупотреблений были недостаточно зрелыми.
Ранее в этом году мы обновили наш интерфейс согласия, чтобы было понятнее, какое приложение запрашивает доступ и какие разрешения оно получит. Мы также добавили отзыв в панель управления, чтобы разработчики могли легко контролировать, какие приложения имеют доступ к их данным, и сделали владение приложениями более заметным для предотвращения фишинговых атак OAuth.
Открытие самоуправляемого OAuth для всех клиентов также потребовало серьёзных обновлений нашего базового движка OAuth. Этот процесс потребовал большого объёма планирования, чтобы минимизировать прерывания для пользователей, обеспечивая при этом стабильность и безопасность данных.
Планирование обновления нашего движка OAuth
Несколько лет назад мы развернули Hydra, движок OAuth с открытым исходным кодом, для работы Cloudflare OAuth. Это развёртывание хорошо служило нам, когда использование было ограниченным, но по мере роста платформы разработчиков и распространения агентных рабочих процессов стало очевидно, что нам нужно серьёзное обновление для открытия новых возможностей и повышения производительности.
При планировании обновления мы решили выполнить два последовательных небольших обновления вместо одного крупного. Сначала мы перешли на последнюю версию 1.X, оценили любые изменения в поведении или производительности, а затем приступили к обновлению до 2.X.
Во время планирования обновления стало ясно, что даже обновление до 1.X повлияет на клиентов, поскольку база данных Hydra требовала обширных миграций схемы, которые:
-
Создавали индексы таким образом, что это блокировало критические таблицы, не позволяя активным пользователям выполнять важные операции OAuth
-
Добавляли столбцы в критические таблицы и перемещали другие столбцы в новые таблицы
Также была особенность в версии Hydra, которую мы использовали: SDK выполнял операции SELECT *, вызывая проблемы десериализации при изменениях схемы.
Чтобы предотвратить влияние на пользователей, мы переписали миграции SQL, используя такие функции, как CREATE INDEX CONCURRENTLY, и создали пользовательскую версию Hydra, которая выбирала явные столбцы вместо SELECT *.
После планирования обновления до последней версии 1.X нам нужно было создать план для ещё более крупного обновления до 2.X. Мы определили три потенциальных варианта и взвесили преимущества и недостатки каждого. Обновление на месте не подходило из-за огромного количества изменений схемы, которые принёс мажорный переход. Мы решили, что стратегия blue-green сработает, но нужно было сделать больше, чем просто переключить выключатель для начала использования новой версии. Процесс обновления и миграции должен был занять несколько часов, и нам нужно было, чтобы система продолжала правильно функционировать в этот промежуток времени.
Первый вариант blue-green предполагал отключение записи в базу данных, предотвращая новые авторизации. Это означало, что они не будут потеряны при переходе, но также означало, что никто не сможет использовать существующие OAuth-приложения, если у них уже нет действительных учётных данных. Это также создавало ещё одну большую проблему: если пользователям нужно было отозвать доступ у приложения по какой-либо причине, это было бы невозможно во время выполнения обновления.
Чтобы решить эти проблемы, мы придумали способ оставить запись в базу данных включённой, ценой потери некоторых данных при переключении на зелёную версию. Первым делом нужно было минимизировать количество записей для новых токенов. Мы использовали оперативный рычаг: увеличение времени истечения токенов до нескольких часов. Это позволило бы приложениям, получившим новые токены до обновления, продолжать их использовать без необходимости обновления.
Решив проблему уменьшения записей, нам нужно было придумать способ не терять отзывы, которые наши пользователи выполняли во время окна обновления. Для этого мы создали систему очередей (используя Cloudflare Queues!), которая после события отзыва записывала запись в очередь с информацией об этом отзыве. Это позволило бы нам опустошить очередь после переключения базы данных на зелёную версию, воспроизводя все события отзыва, произошедшие в промежутке времени, когда они могли быть потеряны. Это было критически важно сделать правильно, иначе приложения, которые пользователи отозвали, случайно восстановили бы свой доступ.
Выполнение обновления
Обновление до 1.X
С операционной точки зрения наше первое обновление до последней версии 1.X прошло без сучка и задоринки. Наши пользовательские миграции базы данных выполнялись быстрее, чем мы ожидали, без влияния на пользователей. Нам пришлось выполнить жёсткое переключение на новую версию, поскольку старая версия не могла интроспектировать токены, созданные новой версией.
После переключения мы заметили увеличение ошибок обновления токенов, которых раньше не видели. Это оказалось связано с более строгим поведением аннулирования при обновлении в новой версии: если токен обновления использовался повторно, Hydra аннулировала всю цепочку токенов доступа и обновления. Это проблематично для клиентов Wrangler и MCP. У обоих этих клиентов высокий объём запросов, и однократное повторное использование токена обновления аннулировало бы весь сеанс.
Мы смягчили это, добавив поведение объединения токенов обновления в наш Worker, который направляет OAuth-трафик к правильному месту назначения. Это позволило нам ненадолго кешировать запрос на обновление токена до того, как он достигал Hydra, так что если мы обнаруживали повторную попытку, мы могли сократить запрос и ответить без аннулирования токенов. К счастью, в версиях Hydra 2.X есть настраиваемый "льготный период обновления токена", который решает эту проблему, позволяя повторять попытку с токеном обновления в течение некоторого времени без аннулирования всей цепочки.
Обновление до 2.X
Поскольку несколько часов высокого воздействия на пользователей были неприемлемы, мы выбрали стратегию blue-green обновления. На высоком уровне это звучит просто: миграции выполнялись на копии нашей производственной базы данных, а затем после их завершения происходило переключение на новую версию Hydra. В реальности было гораздо больше движущихся частей:
-
Включить очередь захвата воспроизведения отзывов
-
Скопировать и восстановить нашу базу данных на новую цель
-
Целевая очистка данных — существующие данные нарушали некоторые новые ограничения, введённые в новых версиях, что могло помешать успешному выполнению миграций
-
Выполнить переключение сервиса Hydra вместе с двумя дополнительными критическими внутренними системами одновременно, чтобы предотвратить любые ошибки
-
Мониторинг и проверка после переключения
Мы выбрали окно обновления, когда Hydra имела наименьший объём запросов в секунду, чтобы минимизировать потерю записей токенов. За исключением настройки некоторых таймаутов, наши производственные миграции прошли хорошо на новой базе данных: чистое время выполнения в производстве составило около трёх часов. После завершения миграций мы осторожно развернули новую версию сервиса Hydra вместе с двумя дополнительными конфигурациями системы, чтобы перевести наши системы на использование новой версии SDK.
Вскоре после переключения трафика мы заметили, что задача очистки данных в нашем сервисе авторизации (который использует Hydra consent session API) была чрезмерно усердной в удалении данных политик OAuth. После расследования мы обнаружили проблему в одной из миграций Hydra, которая повредила состояние некоторых валидных сессий OAuth, что привело к тому, что миграция пометила их как недействительные. Повреждение валидных сессий вызвало расхождение между Hydra и нашим сервисом авторизации, что проявилось в увеличении ошибок 403. Чтобы смягчить это, мы восстановили данные и начали работу над улучшениями поведения авторизации OAuth для устранения зависимости от статических данных политик.
Помимо проблемы с очисткой данных, были и другие небольшие исправления, более обусловленные специфическим поведением клиентов, которые мы быстро внедрили.
После завершения обновления версии Hydra трафик OAuth оставался стабильным, что привело к улучшению производительности системы и надежности для наших клиентов. Это также перевело продакшн на ту же основу, на которой наши новые API OAuth уже были проверены в стейджинге, открыв путь для выпуска самоуправляемого OAuth 3 июня.
Улучшения производительности
После завершения такого крупного обновления всегда полезно и поучительно взглянуть на общие показатели влияния. Мы собрали дополнительные метрики во время миграций базы данных и наблюдали значительное улучшение производительности после завершения обновления.
База данных
| Метрика | Прибл. значение |
|---|---|
| Строк обновлено | 132.5M |
| Строк вставлено | 114.7M |
| Временные байты | 136.97GB |
| Коммитов транзакций | 22.2k |
Производительность Hydra
| Метрика (средн.) | До | После | Изменение |
|---|---|---|---|
| P95 API | 185ms | 101ms | -45% |
| Память RSS | 888MB | 763MB | -14% |
| Выделение кучи Go | 449MB | 271MB | -40% |
| Горутины | 4015 | 3076 | -23% |
| ЦП | 1.07 cores | 0.67 cores | -37% |
Самоуправляемый OAuth для всех
Открытие OAuth для всех клиентов — важный шаг к более широкой экосистеме приложений Cloudflare. Теперь любой клиент Cloudflare может создавать собственные приложения OAuth и строить интеграции на базе Cloudflare. Мы очень рады запустить самоуправляемый OAuth Cloudflare для всех.