Защитите микросервисы с Kong и Ory
18 апреля 2022 г.Микросервисная архитектура в настоящее время является почти стандартом для серверной разработки. Шлюз API — отличный способ подключить группу микросервисов к единому API, доступному для пользователей. Шлюзы API доступны от облачных провайдеров, таких как AWS/Azure/Google Cloud Platform и Cloudflare. Kong — это масштабируемый шлюз API с открытым исходным кодом, который может стать отличной альтернативой, если вы не хотите, чтобы ваша система была привязана к определенному поставщику.
В этом руководстве показан пример использования Kong API gateway, Ory Kratos и Ory Oathkeeper. . На иллюстрации ниже показана окончательная архитектура, которую мы собираемся построить в этом руководстве.
Полный исходный код этого руководства доступен на github
Что будем использовать
- Шлюз Kong может быть отличным решением для входящего балансировщика нагрузки и шлюза API, если вы не хотите привязки к поставщику каких-либо облачных шлюзов API в своем приложении. Конг использует [OpenResty] (https://openresty.org/en/) и Lua. OpenResty расширяет Nginx с помощью сценариев Lua, чтобы использовать модель событий Nginx для неблокирующего ввода-вывода с HTTP-клиентами и удаленными бэкэндами, такими как PostgreSQL, Memcached и Redis. OpenResty — это не форк Nginx, а Kong — не форк Openresty. Конг использует OpenResty для включения [функций шлюза API] (https://microservices.io/patterns/apigateway.html).
- Oathkeeper действует как прокси-сервер идентификации и доступа для наших микросервисов. Это позволяет нам проксировать только аутентифицированные запросы к нашим микросервисам, поэтому нам не нужно внедрять промежуточное ПО для проверки аутентификации. Он также может преобразовывать запросы, например, преобразовывать сеансовую аутентификацию в JWT для внутренней службы.
- Kratos — поставщик аутентификации; он обрабатывает все основные потоки аутентификации: имя пользователя/пароль, забытый пароль, MFA/2FA, [и многое другое] (https://www.ory.sh/docs/kratos/self-service). Он также предоставляет возможности входа в систему OIDC/социальных сетей, например «Войти с помощью GitHub».
Создание простых микросервисов
Допустим, у нас есть два микросервиса: hello и world. Они довольно просты и служат только для тестирования нашего API-шлюза, но вы можете переключить их на более сложные компоненты.
Микросервис World предоставляет конечную точку API /world
и возвращает простое сообщение JSON:
```иди
основной пакет
импорт (
"кодировка/json"
"журнал"
"сеть/http"
введите структуру ответа {
Строка сообщения json:"message"
func helloJSON(w http.ResponseWriter, r *http.Request) {
ответ := Ответ{Сообщение: "Всемирный микросервис"}
w.Header().Set("Тип контента", "приложение/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(ответ)
основная функция () {
http.HandleFunc("/мир", helloJSON)
log.Fatal(http.ListenAndServe(":8090", ноль))
Микросервис «Hello» предоставляет конечную точку API /hello
и возвращает простое сообщение JSON:
```иди
основной пакет
импорт (
"кодировка/json"
"журнал"
"сеть/http"
введите структуру ответа {
Строка сообщения json:"message"
func helloJSON(w http.ResponseWriter, r *http.Request) {
ответ: = Ответ {Сообщение: "Привет, микросервис"}
w.Header().Set("Тип контента", "приложение/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(ответ)
основная функция () {
http.HandleFunc("/привет", приветJSON)
log.Fatal(http.ListenAndServe(":8090", ноль))
Теперь мы хотим защитить доступ к этим микросервисам и предоставить доступ к этим конечным точкам только аутентифицированным пользователям.
Хорошо. Давайте начнем взламывать, не так ли?
Установка Ори Кратоса
Следуйте руководству Quickstart, чтобы настроить Ory Kratos. В этом руководстве вам понадобится только файл docker-compose со следующей конфигурацией:
``ямл
постгрес-кратос:
изображение: постгрес: 9.6
порты:
- "5432:5432"
Окружающая среда:
- POSTGRES_USER=кратос
- POSTGRES_PASSWORD=секрет
- POSTGRES_DB=кратос
сети:
- интранет
Кратос-мигрировать:
изображение: oryd/kratos:v0.8.0-alpha.3
ссылки:
- постгрес-кратос:постгрес-кратос
Окружающая среда:
- DSN=postgres://kratos:secret@postgres-kratos:5432/kratos?sslmode=disable&max_conns=20&max_idle_conns=4
сети:
- интранет
тома:
- тип: связать
источник: ./kratos
цель: /etc/config/kratos
команда: -c /etc/config/kratos/kratos.yml migrate sql -e --yes
Кратос:
изображение: oryd/kratos:v0.8.0-alpha.3
ссылки:
- постгрес-кратос:постгрес-кратос
Окружающая среда:
- DSN=postgres://kratos:secret@postgres-kratos:5432/kratos?sslmode=disable&max_conns=20&max_idle_conns=4
порты:
- '4433:4433'
- '4434:4434'
тома:
- тип: связать
источник: ./kratos
цель: /etc/config/kratos
сети:
- интранет
команда: serve -c /etc/config/kratos/kratos.yml --dev --watch-courier
Кратос-самообслуживание-UI-узел:
изображение: oryd/kratos-selfservice-ui-node:v0.8.0-alpha.3
Окружающая среда:
- KRATOS_PUBLIC_URL=http://kratos:4433/
- KRATOS_BROWSER_URL=http://127.0.0.1:4433/
сети:
- интранет
порты:
- "4455:3000"
перезапуск: при сбое
почтальон:
изображение: oryd/mailslurper:latest-smtps
порты:
- '4436:4436'
- '4437:4437'
сети:
- интранет
Несколько замечаний по сетевой архитектуре:
- HTTP
:4433
и:4434
являются общедоступными и административными API Ори Кратоса.
- HTTP
:4436
для Mailslurper — имитация почтового сервера. Вы можете получить ссылку для активации, перейдя по адресу http://127.0.0.1:4436.
- HTTP
:4455
для интерфейса пользовательского интерфейса, который позволяет запускать потоки регистрации/входа/восстановления.
После запуска docker-compose up вы можете открыть http://127.0.0.1:4455/welcome, чтобы проверить свою конфигурацию.
Настройка Ory Oathkeeper
Теперь мы можем приступить к настройке наших шлюзов для этого примера. Kong является точкой входа для сетевого трафика. Ory Oathkeeper будет доступен из внутренней сети только в этом случае. Давайте рассмотрим нашу архитектурную диаграмму ранее:
Oathkeeper проверяет сеансы и проксирует трафик в наш микросервис, а Kong обеспечивает балансировку входящей нагрузки. Мы даже можем настроить Round-robin DNS, чтобы иметь более надежную конфигурацию для нашего сервиса. Вот как мы настраиваем правила доступа для Ory Oathkeeper:
``ямл
id: "API: привет-защищено"
вверх по течению:
save_host: правда
адрес: "http://привет:8090"
совпадение:
URL-адрес: "http://присягатель:4455/привет"
методы:
- ПОЛУЧИТЬ
аутентификаторы:
обработчик: cookie_session
мутаторы:
- обработчик: нуп
авторизатор:
обработчик: разрешить
ошибки:
- обработчик: перенаправление
конфигурация:
по адресу: http://127.0.0.1:4455/логин
id: "API: защищенный миром"
вверх по течению:
save_host: правда
URL-адрес: "http://мир:8090"
совпадение:
URL-адрес: "http://присягатель:4455/мир"
методы:
- ПОЛУЧИТЬ
аутентификаторы:
обработчик: cookie_session
мутаторы:
- обработчик: нуп
авторизатор:
обработчик: разрешить
ошибки:
- обработчик: перенаправление
конфигурация:
по адресу: http://127.0.0.1:4455/логин
Конфигурация Ory Oathkeeper:
``ямл
журнал:
уровень: отладка
формат: json
обслуживать:
прокси:
кор:
включено: правда
разрешенные_происхождения:
разрешенные_методы:
- СООБЩЕНИЕ
- ПОЛУЧИТЬ
- ПОМЕЩАТЬ
- ПЛАСТЫРЬ
- УДАЛЯТЬ
разрешенные_заголовки:
- Авторизация
- Тип содержимого
выставленные_заголовки:
- Тип содержимого
allow_credentials: правда
отладка: правда
ошибки:
отступать:
- json
обработчики:
перенаправить:
включено: правда
конфигурация:
по адресу: http://127.0.0.1:4455/логин
когда:
ошибка:
- несанкционированный
- запрещенный
запрос:
заголовок:
принимать:
- текст/html
json:
включено: правда
конфигурация:
подробно: правда
правила_доступа:
match_strategy: глобус
репозитории:
- файл:///etc/config/oathkeeper/access-rules.yml
аутентификаторы:
анонимно:
включено: правда
конфигурация:
тема: гость
cookie_session:
включено: правда
конфигурация:
check_session_url: http://kratos:4433/sessions/whoami
сохранить_путь: правда
extra_from: "@это"
subject_from: "identity.id"
Только:
- ory_kratos_session
нет:
включено: правда
авторизаторы:
разрешать:
включено: правда
мутаторы:
нет:
включено: правда
Ory Oathkeeper теперь ищет действительный сеанс в файлах cookie запросов и проксирует только аутентифицированные запросы. Он перенаправляет на интерфейс входа в систему, если файл cookie ory_kratos_session недоступен.
Добавление Конга
Теперь осталось настроить Kong:
``ямл
Сервисы:
конг-миграции:
изображение: "конг:последний"
команда: начальная загрузка конг миграции
зависит от:
- дб
Окружающая среда:
<<: *kong-env
сети:
- интранет
перезапуск: при сбое
конг:
платформа: линукс/арм64
изображение: "конг:последний"
Окружающая среда:
<<: *kong-env
KONG_ADMIN_ACCESS_LOG: /dev/stdout
KONG_ADMIN_ERROR_LOG: /dev/stderr
KONG_PROXY_LISTEN: "${KONG_PROXY_LISTEN:-0.0.0.0:8000}"
KONG_ADMIN_LISTEN: "${KONG_ADMIN_LISTEN:-0.0.0.0:8001}"
KONG_PROXY_ACCESS_LOG: /dev/stdout
KONG_PROXY_ERROR_LOG: /dev/stderr
KONG_PREFIX: ${KONG_PREFIX:-/var/run/kong}
KONG_DECLARATIVE_CONFIG: "/opt/kong/kong.yaml"
сети:
- интранет
порты:
Следующие две переменные среды по умолчанию имеют небезопасное значение (0.0.0.0)
согласно тесту CIS Security.
- "${KONG_INBOUND_PROXY_LISTEN:-0.0.0.0}:8000:8000/TCP"
- "${KONG_INBOUND_SSL_PROXY_LISTEN:-0.0.0.0}:8443:8443/TCP"
- "127.0.0.1:8001:8001/TCP"
- "127.0.0.1:8444:8444/TCP"
проверка состояния здоровья:
тест: ["CMD", "конг", "здоровье"]
интервал: 10 с
тайм-аут: 10 сек.
повторы: 10
перезапуск: при сбое: 5
только для чтения: правда
тома:
- kong_prefix_vol:${KONG_PREFIX:-/var/run/kong}
- kong_tmp_vol:/tmp
- ./config:/опт/конг
security_opt:
- нет-новых-привилегий
дБ:
изображение: постгрес: 9.6
Окружающая среда:
POSTGRES_DB: конг
POSTGRES_USER: конг
POSTGRES_PASSWORD: конг
проверка состояния здоровья:
тест: ["CMD", "pg_isready", "-U", "конг"]
интервал: 30 с
тайм-аут: 30 сек.
повторы: 3
перезапуск: при сбое
сети:
- интранет
привет:
Docker-compose создает три контейнера
- Контейнер db с базой данных PostgreSQL для хранения конфигурации сервисов/маршрутов для нашего шлюза API.
- kong-migrate для запуска миграций базы данных.
- Контейнер kong, предоставляющий порт 8000 для проксирования трафика и порт 8001 для API администратора.
В качестве последнего шага нам нужно создать сервис для Kong и настроить маршруты.
``` ударить
!/бин/баш
Создает безопасный API-сервис
и проксирует сетевой трафик на oathkeeper
завиток -i -X ПОСТ \
--url http://localhost:8001/services/ \
--data 'имя=secure-api' \
--data 'url=http://присягатель:4455'
Создает маршруты для сервиса secure-api
завиток -i -X ПОСТ \
--url http://localhost:8001/services/secure-api/routes\
--data 'пути[]=/'\
Тестирование
Вы можете открыть http://127.0.0.1:8000/hello или http://127.0.0.1:8000/world в своем браузере, и есть два возможных сценария:
- Вы получаете
{"message": "Hello microservice"}
(или"World microservice"
).
- Браузер перенаправляет вас на http://127.0.0.1:4455/login.
Дальнейшие шаги
- [Настройте] (https://www.ory.sh/docs/kratos/guides/zero-trust-iap-proxy-identity-access-proxy) мутатор id_token, чтобы удостоверение было доступно в качестве токена JWT для ваших микросервисов. .
- Настройте политику паролей, чтобы она лучше соответствовала вашему варианту использования.
- Рассмотрите возможность использования аутентификации на основе результата подзапроса вместо дополнительного обратного прокси-сервера внутри вашей сети.
- Kong auth request может быть отличным плагином для использования Oathkeeper в качестве API принятия решений для Kong.
Оригинал