Шлюз API шаблон реализует услугу , что это точка входа в microservices приложение, от внешних клиентов API или потребителей.
Он отвечает за маршрутизацию запросов, составление API и другие граничные функции, такие как аутентификация.
При работе с архитектурой микросервисов, будь то проект с нуля или переход от монолита, лучше всего приступить к решению сквозных задач. Аутентификация является такой проблемой, и в этой статье мы рассмотрим аутентификацию мультитенантного приложения .
Существует множество технологий, которые мы можем использовать для реализации шаблона API-шлюза, включая готовые продукты API-шлюза, такие как Kong .
Когда он получает запрос, Kong выполняет поиск в карте маршрутизации, которая указывает, какой восходящий сервис направить запрос. Эта функция идентична функции обратного прокси, предоставляемой веб-серверами, такими как NGINX. Kong основан на HTTP-сервере NGINX и позволяет нам настраивать гибкие правила маршрутизации, которые используют метод HTTP, заголовки и путь для выбора службы backend / upstream, а также предоставляет набор плагинов, которые реализуют функции пограничного уровня, такие как аутентификация: acl и ключ аутентификации .
Давайте не будем рассматривать следующие предварительные условия и шаги для реализации аутентификации на основе API-ключей:
- myService — микросервис, который должен быть закрытым и предоставлять конечную точку http: // myServicePrivateHost: 80 / api / v1 / myServicePath
- два арендатора tenant1.mydomain.com и tenant2.mydomain.com, для которых мы хотим аутентифицировать запросы
- Kong работает на http: // localhost: 8000 для прокси и http: // localhost: 8001 для API администратора
1. Создать сервисный объект , представление вышестоящего микросервиса
Запрос:
Оболочка
x
1
curl -X POST \
2
http://localhost:8001/services \
3
-H 'Content-Type: application/json' \
4
-d '{
5
"host": "myServicePrivateHost",
6
"name": "myService"
7
}'
Отклик:
Оболочка
x
1
{
2
"host": "myServicePrivateHost",
3
"created_at": 1577460734,
4
"connect_timeout": 60000,
5
"id": "110a66e0-ab86-495d-9fc7-1ade0eea6f41",
6
"protocol": "http",
7
"name": "myService",
8
"read_timeout": 60000,
9
"port": 80,
10
"path": null,
11
"updated_at": 1577460734,
12
"retries": 5,
13
"write_timeout": 60000,
14
"tags": null,
15
"client_certificate": null
16
}
2. Создайте объект маршрута для каждого арендатора
- идентификатор сервиса — извлекается из ответа шага 1
- hosts — поле, содержащее фактический домен, специфичный для арендатора
- имя маршрута — должно быть уникальным и в этом случае оно должно начинаться с имени арендатора
Запрос:
Оболочка
x
1
curl -X POST \
2
http://localhost:8001/routes \
3
-H 'Content-Type: application/json' \
4
-d '{
5
"protocols": [
6
"http",
7
"https"
8
],
9
"service": {
10
"id": "110a66e0-ab86-495d-9fc7-1ade0eea6f41"
11
},
12
"name": "tenant1.routeForMyService",
13
"preserve_host": false,
14
"regex_priority": 0,
15
"strip_path": false,
16
"paths": [
17
"/api/v1/myServicePath"
18
],
19
"hosts": [
20
"tenant1.mydomain.com"
21
],
22
"methods": [
23
"GET"
24
]
25
}'
Примечание . Выполните тот же запрос на текущем шаге и замените
tenant1 на
tenant2 с целью создания маршрута для другого арендатора.
Когда поступит запрос, Kong будет использовать заголовок хоста, путь и метод HTTP для выбора маршрута. Если маршрут не найден, ответом будет:
Оболочка
xxxxxxxxxx
1
{
2
"message": "no Route matched with those values"
3
}
На данный момент у нас есть два неаутентифицированных маршрута, и мы создадим потребителя для каждого из них. Такими потребителями могут быть клиентские приложения или пользователи, и они могут иметь несколько ключей API.
3. Создать потребительский объект для каждого арендатора
Запрос:
Оболочка
xxxxxxxxxx
1
curl --request POST \
2
--url http://localhost:8001/consumers \
3
--header 'Content-Type: application/json' \
4
--data '{"username":"someConsumerForTenant1"}'
Примечание . Выполните тот же запрос на текущем шаге и замените
tenant1 на
tenant2 с целью создания потребителя для другого арендатора.
Теперь мы должны сгруппировать потребителей по конкретному арендатору (есть также случаи, когда мы хотим группировать по заявке арендатора), и указанное имя группы будет занесено в белый список для использования API.
4. Создайте группу для каждого потребителя
Запрос:
Оболочка
xxxxxxxxxx
1
curl --request POST \
2
--url http://localhost:8001/consumers/someConsumerForTenant1/acls \
3
--header 'Content-Type: application/json' \
4
--data '{"group":"tenant1Group"}'
Примечание . Выполните тот же запрос на текущем шаге и замените
tenant1 на
tenant2 с целью создания группы для другого арендатора.
5. Применение плагина key-auth для конкретного маршрута клиента
Запрос:
Оболочка
xxxxxxxxxx
1
curl --request POST \
2
--url http://localhost:8001/routes/tenant1.routeForMyService/plugins \
3
--header 'Content-Type: application/json' \
4
--data '{"name":"key-auth"}'
Примечание . Выполните тот же запрос на текущем шаге и замените
tenant1 на
tenant2 с целью применения плагина для другого маршрута арендатора.
6. Применение подключаемого модуля acl для конкретного маршрута клиента
Запрос:
Оболочка
x
1
curl --request POST \
2
--url http://localhost:8001/routes/tenant1.routeForMyService/plugins \
3
--header 'Content-Type: application/json' \
4
--data '{"name":"acl", "config":{"whitelist":["tenant1Group"]}}'
Примечание . Выполните тот же запрос на текущем шаге и замените
tenant1 на
tenant2 с целью применения плагина для другого маршрута арендатора.
7. Сгенерируйте ключ API для tenant1 :
Запрос:
Оболочка
x
1
curl --request POST \
2
--url http://localhost:8001/consumers/someConsumerForTenant1/key-auth \
3
--header 'Content-Type: application/json' \
4
--data '{}'
Отклик:
Оболочка
xxxxxxxxxx
1
{
2
"key": "6DlgBFKA2a0uD9CHVgqQvsZfWsePC0zu",
3
"created_at": 1577462044,
4
"consumer": {
5
"id": "47dd2c7b-8094-4a9f-96f0-15120ddb8a79"
6
},
7
"id": "40c69ad1-37f8-4551-ab66-eb3609e78f26"
8
}
8. Откройте / api / v1 / myServicePath для tenant1 без заголовка apikey:
Запрос:
Оболочка
x
1
curl --request GET \
2
--url http://localhost:8000/api/v1/myServicePath \
3
--header 'host: tenant1.mydomain.com'
Отклик:
Оболочка
xxxxxxxxxx
1
{
2
"message": "No API key found in request"
3
}
9. Получите доступ к / api / v1 / myServicePath для tenant1 с соответствующим ключом API, сгенерированным на шаге 7:
Запрос:
Оболочка
x
1
curl --request GET \
2
--url http://localhost:8000/api/v1/myServicePath \
3
--header 'apikey: 6DlgBFKA2a0uD9CHVgqQvsZfWsePC0zu' \
4
--header 'host: tenant1.mydomain.com'
Отклик:
Оболочка
xxxxxxxxxx
1
{
2
"message": "name resolution failed"
3
}
Примечание . Ответ зависит от действующего микросервиса, развернутого локально. Если он запущен и работает, он вернет правильный ответ. В нашем случае сервис не существует, поэтому он вернет сервис 503, временно недоступный, и ответ выше.
10. Откройте / api / v1 / myServicePath для tenant2 с помощью ключа api арендатора1 :
Отклик:
Оболочка
xxxxxxxxxx
1
{
2
"message": "You cannot consume this service"
3
}
Эти шаги могут быть дополнительно автоматизированы путем создания оболочки через Kong Admin API. Фактически это будет микросервис, с которым будут взаимодействовать другие службы (например, IAM — управление идентификацией и доступом — микросервис, отвечающий за аутентификацию и авторизацию) в качестве средства для генерации потребителей и API-ключей для этих потребителей.
Таким образом, мы можем использовать Kong API Gateway для централизации аутентификации в нашем многопользовательском приложении.