Практика шлюза API в облачной архитектуре: Конг (3)

задняя часть Архитектура

В предыдущей статье была представлена ​​соответствующая практика Конга,Ссылка на статью, в этой статье будут представлены мощные инструменты 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 создается, как описано выше.

После создания пользователя вам необходимо получить учетные данные пользователя JWT и выполнить следующий вызов:

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 в облачной архитектуре

Подписывайтесь на свежие статьи, приглашаю обратить внимание на мой публичный номер

微信公众号