В предыдущей статье была представлена соответствующая практика Конга,Ссылка на статью, в этой статье будут представлены мощные инструменты Kong: плагины и пользовательские плагины.
Применение нескольких распространенных плагинов в Kong
Когда запрос поступает в Kong, прежде чем перенаправить его серверному приложению, мы можем использовать подключаемый модуль, поставляемый с Kong, для обработки запроса, такой как юридическая аутентификация, контроль текущих ограничений, проверка черного и белого списков, сбор журналов и скоро. В то же время мы также можем настраивать и разрабатывать собственные плагины в соответствии с учебной документацией Kong. В этом разделе будут выбраны два примера подключаемых модулей. Остальные подключаемые модули см. по адресу:docs.emptylogistics.com/Hubei/.
Плагин аутентификации JWT
JWT в настоящее время является самым популярным решением для междоменной аутентификации. В качестве открытого стандарта (RFC 7519) он определяет краткий автономный метод для безопасной передачи информации в виде объектов JSON между взаимодействующими сторонами. Из-за наличия цифровой подписи информации доверяют.
О том, зачем используется JWT, подробно в этом разделе не говорится, см.Проектирование и практика унифицированной аутентификации и авторизации в микросервисной архитектуре. Kong предоставляет подключаемый модуль аутентификации JWT для проверки запросов, содержащих JWT с подписями HS256 или RS256 (как описано в RFC 7519). Каждый потребитель будет иметь учетные данные JWT (открытый и секретный ключи), которые необходимо использовать для подписи их JWT. Токены JWT можно передавать через строки запроса, файлы cookie или заголовки аутентификации. Kong проверит подпись токена и перешлет его, если он пройдет, в противном случае запрос будет напрямую отклонен.
На основе маршрутизации, настроенной в предыдущем разделе, мы добавляем подключаемый модуль аутентификации JWT.
curl -X POST http://localhost:8001/routes/e33d6aeb-4f35-4219-86c2-a41e879eda36/plugins \
--data "name=jwt"
Как видите, соответствующая запись добавлена в список плагинов.
После добавления плагина JWT прямого доступа нет/api/blogинтерфейс, интерфейс возвращает:"message": "Unauthorized". Предлагает клиенту получить доступ к данным аутентификации, для которых требуется JWT. Поэтому нам нужно создать пользователей:
curl -i -X POST \
--url http://localhost:8001/consumers/ \
--data "username=aoho"
Пользователь с именем aoho создается, как описано выше.
curl -i -X POST \
--url http://localhost:8001/consumers/aoho/jwt \
--header "Content-Type: application/x-www-form-urlencoded"
// 响应
{
"rsa_public_key": null,
"created_at": 1563566125,
"consumer": {
"id": "8c0e1ab4-8411-42fc-ab80-5eccf472d2fd"
},
"id": "1d69281d-5083-4db0-b42f-37b74e6d20ad",
"algorithm": "HS256",
"secret": "olsIeVjfVSF4RuQuylTMX4x53NDAOQyO",
"key": "TOjHFM4m1qQuPPReb8BTWAYCdM38xi3C"
}
использовать ключ и секрет вhttps://jwt.ioМожно создать учетную информацию JWT. В процессе фактического использования мы реализуем его посредством кодирования.Здесь мы используем веб-инструменты для создания токена для демонстрации.
Настройте сгенерированный токен на заголовок аутентификации запроса и снова выполните запрос:
Как видите, мы можем запросить соответствующий интерфейс API в обычном режиме. Плагин аутентификации JWT успешно применен.
Визуальный мониторинг Прометея
Prometheus — это система мониторинга и оповещения с открытым исходным кодом. Вдохновленный системой мониторинга Google borgmon, он был создан в 2012 году бывшими сотрудниками Google, работающими в SoundCloud, разработан как проект сообщества с открытым исходным кодом и официально выпущен в 2015 году. В 2016 году Prometheus официально присоединился к Cloud Native Computing Foundation, став вторым по популярности проектом после Kubernetes. В качестве платформы мониторинга нового поколения Prometheus подходит для записи данных временных рядов, предлагая мощную многомерную модель данных, гибкие и мощные операторы запросов, а также простое управление и масштабирование.
Официальный плагин Prometheus, предоставленный Kong, доступны следующие показатели:
- Код состояния: код состояния HTTP, возвращаемый вышестоящей службой;
- Гистограмма задержки: будут записаны все задержки в Kong, включая следующие:
- запрос: задержка полного запроса;
- Kong: время, затрачиваемое Kong на маршрутизацию, аутентификацию и запуск других плагинов;
- Upstream: время, затраченное восходящей службой на ответ на запрос.
- Полоса пропускания: общая пропускная способность (исходная/входящая), проходящая через Kong;
- Доступность БД: может ли узел Kong получить доступ к своей БД;
- Соединения: различные метрики соединения NGINX, такие как «Активные», «Чтение», «Запись», «Принятые соединения».
Устанавливаем плагин Prometheus на сервис, сервис которого aoho-blog:
curl -X POST http://localhost:8001/services/aoho-blog/plugins \
--data "name=prometheus"
Как видно из интерфейса управления, мы успешно привязали плагин Prometheus к сервису aoho-blog.
посетив/metricsИнтерфейс возвращается к сбору данных метрик:
$ curl -i http://localhost:8001/metrics
HTTP/1.1 200 OK
Server: openresty/1.13.6.2
Date: Sun, 21 Jul 2019 09:48:42 GMT
Content-Type: text/plain; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Access-Control-Allow-Origin: *
kong_bandwidth{type="egress",service="aoho-blog"} 178718
kong_bandwidth{type="ingress",service="aoho-blog"} 1799
kong_datastore_reachable 1
kong_http_status{code="200",service="aoho-blog"} 4
kong_http_status{code="401",service="aoho-blog"} 1
kong_latency_bucket{type="kong",service="aoho-blog",le="00005.0"} 1
kong_latency_bucket{type="kong",service="aoho-blog",le="00007.0"} 1
...
kong_latency_bucket{type="upstream",service="aoho-blog",le="00300.0"} 4
kong_latency_bucket{type="upstream",service="aoho-blog",le="00400.0"} 4
...
kong_latency_count{type="kong",service="aoho-blog"} 5
kong_latency_count{type="request",service="aoho-blog"} 5
kong_latency_count{type="upstream",service="aoho-blog"} 4
kong_latency_sum{type="kong",service="aoho-blog"} 409
kong_latency_sum{type="request",service="aoho-blog"} 1497
kong_latency_sum{type="upstream",service="aoho-blog"} 1047
kong_nginx_http_current_connections{state="accepted"} 2691
kong_nginx_http_current_connections{state="active"} 2
kong_nginx_http_current_connections{state="handled"} 2691
kong_nginx_http_current_connections{state="reading"} 0
kong_nginx_http_current_connections{state="total"} 2637
kong_nginx_http_current_connections{state="waiting"} 1
kong_nginx_http_current_connections{state="writing"} 1
kong_nginx_metric_errors_total 0
Возвращаемый ответ слишком длинный и опущен. Из ответа видно, что отражены метрики, предоставленные плагином Prometheus. Метрики, экспортируемые плагином Prometheus, могут быть отображены в Grafana, и читатели могут попробовать это сами.
Плагин отслеживания ссылок Zipkin
Zipkin — это распределенная система отслеживания данных в реальном времени с открытым исходным кодом. Его основная функция заключается в объединении данных мониторинга в реальном времени из различных разнородных систем для отслеживания проблемы системной задержки в рамках микросервисной архитектуры. Прикладная система должна сообщать данные Zipkin. Подключаемый модуль Kong Zipkin в качестве zipkin-клиента предназначен для сборки пакетов данных, необходимых для Zipkin, и отправки данных на Zipkin-сервер. Плагин Zipkin пометит запрос следующим образом и отправит его на сервер Zipkin:
- span.kind (отправлено Зипкину как «вид»)
- http.method
- http.status_code
- http.url
- peer.ipv4
- peer.ipv6
- peer.port
- peer.hostname
- peer.service
Подробную информацию о трассировке ссылок и Zipkin см.Подробное объяснение полного отслеживания ссылок в микросервисной архитектуре., цель этого чата — показать, как использовать плагин Zipkin для отслеживания связи всех запросов в Kong.
Сначала откройте плагин Zipkin и привяжите его к маршруту (его можно привязать как глобальный плагин).
curl -X POST http://kong:8001/routes/e33d6aeb-4f35-4219-86c2-a41e879eda36/plugins \
--data "name=zipkin" \
--data "config.http_endpoint=http://localhost:9411/api/v2/spans" \
--data "config.sample_ratio=1"
Адрес и частота дискретизации Zipkin Collector настраиваются, как указано выше. Для очевидного эффекта установите частоту дискретизации на 100%. Используйте ее с осторожностью в производственной среде. Частота дискретизации влияет на пропускную способность системы.
Как видите, плагин Zipkin был применен к указанному маршруту. Далее мы выполним запрос/api/blogинтерфейс, открытыйhttp://localhost:9411Интерфейс выглядит следующим образом:
Zipkin записал запрос, мы можем щелкнуть, чтобы просмотреть подробные сведения о ссылке:
Из вызова ссылки вы можете узнать, какие службы и интервалы использовались после того, как запрос достиг Kong, время, затраченное на каждый интервал, и так далее.
Практика с пользовательскими плагинами
Несмотря на то, что официальные подключаемые модули предоставляют множество подключаемых модулей, у нас все еще есть бизнес-потребности в реальных бизнес-сценариях, и настраиваемые подключаемые модули могут помочь нам лучше управлять шлюзом API. Kong предоставляет наборы для разработки подключаемых модулей и примеры, а для создания пользовательских подключаемых модулей необходимо выполнить только указанные шаги.
Установка Конга
В приведенном выше разделе автор представил установку Kong зеркалированием.В этой части, чтобы облегчить написание пользовательских плагинов, мы используем локально установленный Kong.Среда автора - macOS, и установка относительно проста :
$ brew tap kong/kong
$ brew install kong
Затем установите Postgres и загрузите файл конфигурации kong.conf.default (см.Пользовательское содержимое raw.GitHub.com/Kong/empty/none…
$ sudo mkdir -p /etc/kong
$ sudo cp kong.conf.default /etc/kong/kong.conf
Выполнить миграцию:
kong migrations bootstrap -c /etc/kong/kong.conf
Затем вы можете запустить Kong:
kong start -c /etc/kong/kong.conf
После загрузки проверьте успешность через порт управления 8001.
curl -i http://localhost:8001/
Основываясь на установленном Kong, давайте представим, как добавить пользовательские плагины к дополнительным плагинам Kong. Здесь мы возьмем плагин аутентификации с токеном аутентификации в качестве примера для объяснения.
Kong официально предоставляет подключаемые модули, связанные с аутентификацией: JWT, OAuth 2.0, Basic Auth и т. д. В реальном бизнесе мы часто строим собственный сервер аутентификации и авторизации, что требует от нас перехвата валидности запроса на проверку на шлюзе API. Исходя из этого, мы реализуем плагин, аналогичный фильтру Kong: token-auth.
Плагин, который поставляется с Kong, находится в/usr/local/share/lua/5.1/kong/plugins/Под содержанием. Каждая папка плагина имеет следующие два основных файла:
- schema.lua: определена проверка параметров при запуске плагина;
- handler.lua: файл определяет функции, выполняемые на каждом этапе, ядро плагина.
token-auth — это имя нашего пользовательского плагина. существует/usr/local/share/lua/5.1/kong/pluginsСоздайте новый каталог token-auth в разделе. Этапы загрузки и инициализации плагина, а именноKong.init()При загрузке плагина будут загружены schema.lua и handler.lua в каталоге плагина Давайте посмотрим на реализацию этих двух скриптов.
Определение конфигурации плагина: schema.lua
Конфигурация каждого плагина в Kong хранится в поле config в таблице плагинов, которая представляет собой фрагмент текста json.Конфигурация, необходимая для токена-аутентификации, определяется следующим образом:
return {
no_consumer = true,
fields = {
auth_server_url = {type = "url", required = true},
}
}
Как видно из schema.lua, при включении плагина token-auth необходимо проверить, что поле auth_server_url имеет тип URL и не может быть пустым.
Реализация функции плагина: handler.lua
handler.lua реализует функцию аутентификации плагина, методы, определенные в этом плагине, будут вызываться при обработке запросов и ответов.
llocal http = require "socket.http"
local ltn12 = require "ltn12"
local cjson = require "cjson.safe"
local BasePlugin = require "kong.plugins.base_plugin"
local TokenAuthHandler = BasePlugin:extend()
TokenAuthHandler.PRIORITY = 1000
local KEY_PREFIX = "auth_token"
local EXPIRES_ERR = "token expires"
--- 提取 JWT 头部信息
-- @param request ngx request object
-- @return token JWT
-- @return err
local function extract_token(request)
local auth_header = request.get_headers()["authorization"]
if auth_header then
local iterator, ierr = ngx.re.gmatch(auth_header, "\\s*[Bb]earer\\s+(.+)")
if not iterator then
return nil, ierr
end
local m, err = iterator()
if err then
return nil, err
end
if m and #m > 0 then
return m[1]
end
end
end
--- 调用 auth server 验证 token 合法性
-- @param token Token to be validated
-- @param conf Plugin configuration
-- @return info Information associated with token
-- @return err
local function query_and_validate_token(token, conf)
ngx.log(ngx.DEBUG, "get token info from: ", conf.auth_server_url)
local response_body = {}
local res, code, response_headers = http.request{
url = conf.auth_server_url,
method = "GET",
headers = {
["Authorization"] = "bearer " .. token
},
sink = ltn12.sink.table(response_body),
}
if type(response_body) ~= "table" then
return nil, "Unexpected response"
end
local resp = table.concat(response_body)
ngx.log(ngx.DEBUG, "response body: ", resp)
if code ~= 200 then
return nil, resp
end
local decoded, err = cjson.decode(resp)
if err then
ngx.log(ngx.ERR, "failed to decode response body: ", err)
return nil, err
end
if not decoded.expires_in then
return nil, decoded.error or resp
end
if decoded.expires_in <= 0 then
return nil, EXPIRES_ERR
end
decoded.expires_at = decoded.expires_in + os.time()
return decoded
end
function TokenAuthHandler:new()
TokenAuthHandler.super.new(self, "token-auth")
end
--- 实现 access 方法
function TokenAuthHandler:access(conf)
TokenAuthHandler.super.access(self)
local token, err = extract_token(ngx.req)
if err then
ngx.log(ngx.ERR, "failed to extract token: ", err)
return kong.response.exit(500, { message = err })
end
ngx.log(ngx.DEBUG, "extracted token: ", token)
local ttype = type(token)
if ttype ~= "string" then
if ttype == "nil" then
return kong.response.exit(401, { message = "Missing token"})
end
if ttype == "table" then
return kong.response.exit(401, { message = "Multiple tokens"})
end
return kong.response.exit(401, { message = "Unrecognized token" })
end
local info
info, err = query_and_validate_token(token, conf)
if err then
ngx.log(ngx.ERR, "failed to validate token: ", err)
if EXPIRES_ERR == err then
return kong.response.exit(401, { message = EXPIRES_ERR })
end
return kong.response.exit(500,{ message = EXPIRES_ERR })
end
if info.expires_at < os.time() then
return kong.response.exit(401, { message = EXPIRES_ERR })
end
ngx.log(ngx.DEBUG, "token will expire in ", info.expires_at - os.time(), " seconds")
end
return TokenAuthHandler
Плагин token-auth реализует два метода, new() и access(), которые работают только на этапе доступа. В методе access() информация заголовка JWT сначала извлекается, чтобы проверить, существует ли токен, верен ли его формат и т. д., а затем запрашивается сервер аутентификации для проверки действительности токена.
Загрузить плагин
После завершения разработки плагина сначала создайте файл token-auth-1.2.1-0.rockspec в каталоге плагина и залейте только что разработанный плагин:
package = "token-auth"
version = "1.2.1-0"
supported_platforms = {"linux", "macosx"}
local pluginName = "token-auth"
build = {
type = "builtin",
modules = {
["kong.plugins.token-auth.handler"] = "kong/plugins/token-auth/handler.lua",
["kong.plugins.token-auth.schema"] = "kong/plugins/token-auth/schema.lua",
}
}
Затем добавьте только что разработанный плагин в конфигурационный файл kong.conf:
$ vim /etc/kong/kong.conf
# 去掉开头的注释并修改如下
plugins = bundled, token-auth
Атрибут bundled относится к официально предоставленной коллекции плагинов, которая включена по умолчанию. Здесь мы добавили пользовательский плагин аутентификации по токену. Убедитесь, что пользовательский плагин успешно загружен:
$ curl http://127.0.0.1:8001/plugins/enabled
{"enabled_plugins":["correlation-id","pre-function","cors","token-auth","ldap-auth","loggly","hmac-auth","zipkin","request-size-limiting","azure-functions","request-transformer","oauth2","response-transformer","ip-restriction","statsd","jwt","proxy-cache","basic-auth","key-auth","http-log","datadog","tcp-log","post-function","prometheus","acl","kubernetes-sidecar-injector","syslog","file-log","udp-log","response-ratelimiting","aws-lambda","bot-detection","rate-limiting","request-termination"]}%
Включить плагин
Чтобы включить плагин token-auth в Сервисе, вам нужно указать свойство config.auth_server_url:
$ curl -i -XPOST localhost:8001/services/aoho-blog/plugins \
--data 'name=token-auth' \
--data 'config.auth_server_url=<URL of verification API>'
Если подключаемый модуль имеет собственную таблицу базы данных или имеет требования к таблице базы данных или данным в таблице, создайте каталог миграции в каталоге подключаемого модуля. Создайте файл migrations/postgres.lua или migrations/cassandra.lua в зависимости от того, используете ли вы Postgres или Cassandra.
Если плагин имеет свою собственную таблицу базы данных, вам также необходимо создать daos.lua в каталоге плагина, чтобы вернуть определение таблицы базы данных.Если нет отдельной таблицы базы данных, вам не нужно создавать этот файл.
Я не буду делать здесь слишком много демонстрации, читатели могут объединить предыдущий чат автора:Проектирование и практика унифицированной аутентификации и авторизации в микросервисной архитектуре, создайте сервер аутентификации и авторизации и попробуйте сами.
резюме
Шлюз – незаменимый базовый сервис в архитектуре микросервисов. В этой статье рассказывается, как использовать Kong для создания шлюза микросервисов. По сравнению с другими компонентами шлюза Kong отличается простотой использования и производительностью, что делает его современным облачным шлюзом. Затем вводятся некоторые плагины Kong. Официальный представитель Kong и сообщество предоставляют множество подключаемых модулей шлюза API, которые можно использовать после настройки. Наконец, в этой статье автор реализует настраиваемый подключаемый модуль аутентификации по токену. Открытый механизм подключаемого модуля Kong позволяет разработчикам гибко реализовывать особые потребности бизнеса.
Рекомендуемое чтение
Практика шлюза API в облачной архитектуре