前言

上文有提到,我们是要在kong中开发一个"统一鉴权服务"。因此需要开发一个自定义的lua插件来满足业务需求。

开发插件


First, we need to create either a ConfigMap or a Secret with the plugin code inside it. If you would like to install a plugin which is available as a rock from Luarocks, then you need to download it, unzip it and create a ConfigMap from all the Lua files of the plugin.

插件结构

一个标准的Kong插件的目录结构是: kong.plugins.<plugin_name>.<module_name>

[root@dev-node1 plugins]# tree kong/
kong/
└── plugins
    └── verify
        ├── handler.lua
        └── schema.lua

2 directories, 2 files
[root@dev-node1 plugins]# pwd
/opt/kong/plugins
  • /opt/kong/plugins: 插件的工作目录, 类似于java的工程目录下的 src ,用户可以随意指定到其他位置.
  • kong/plugins: 插件的标准目录树.可以理解为java中的标准父包名,用户不可修改。
  • verify: 代表插件名称包路径. 学名: plugin_name。
  • *.lua: 插件业务模块。

关于 handler.lua schema.lua

handler.lua : the core of your plugin. It is an interface to implement, in which each function will be run at the desired moment in the lifecycle of a request / connection.

handler.lua : 此文件是插件核心功能. 此文件是继承了一个通用接口, 实现了一些具体业务方法.在具体的http请求的生命周期中, 这些方法会被调用, 从而实现插件的功能.

schema.lua: your plugin probably has to retain some configuration entered by the user. This module holds the schema of that configuration and defines rules on it, so that the user can only enter valid configuration values.。

schema.lua : 用于接收和维护管理员对此插件的自定义参数设置信息.

handler.lua

local base_plugin  = require("kong.plugins.base_plugin")

local verify = base_plugin:extend()

local kong = kong

verify.VERSION  = "1.0"
verify.PRIORITY = 10

function verify:new()
    verify.super.new(self, "verify-plugin")
end

function verify.access(self, config)
    verify.super.access(self)

    kong.log.inspect(config)

    kong.log.info("Header Name: ", config.header_name)
    kong.log.info("Header Value: ", config.header_value)

    kong.service.request.add_header(config.header_name, config.header_value)
end

function verify.header_filter(self, config)
    verify.super.header_filter(self)
    kong.response.set_header("verify", "tianxiaoyong")
end

function verify.body_filter(self, config)
    verify.super.body_filter(self)
    kong.log.info("Coming into body_filter_phase")
end

function verify.log(self, config)
    verify.super.log(self)
    kong.log.info("Coming into log_phase")
end

return verify

schema.lua

local typedefs = require "kong.db.schema.typedefs"


return {
  name = "verify",
  fields = {
    {
      config = {
        type = "record",
        fields = {
          {
            header_name = {
              type = "string",
              required = true
            }
          },
          {
            header_value = {
              type = "string",
              required = true
            }
          },
        }
      }
    }
  }
}

部署插件


用插件代码创建一个ConfigMap或Secret

[root@k8s-master verify]# cd ..
[root@k8s-master kong-install]# ll
total 69
drwxr-xr-x.  2 root root       69 Sep 16 22:15 verify
[root@k8s-master kong-install]# pwd
/root/kong-install
[root@k8s-master kong-install]# kubectl create configmap kong-plugin-verify-cm --from-file=verify -n kong
configmap/kong-plugin-verify-cm created

修改配置文件

这里菜菜只介绍yaml方式,因为helm我并没有用过。

  1. 将插件代码移动到pod中并配置属性volumeMounts以及volumes。
  2. 默认情况下,KONG_PLUGINS环境变量设置为包括自定义插件以及Kong中附带的所有插件。
  3. KONG_LUA_PACKAGE_PATH环境变量指示Kong在我们安装它们的目录中寻找插件。

如果您有多个插件,只需安装多个ConfigMaps并将插件名称包含在环境变量中即可。

为我们已经存在的kong ingress controller打一个插件补丁:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ingress-kong
  namespace: kong
spec:
  template:
    spec:
      containers:
      - name: proxy
        env:
        - name: KONG_PLUGINS
          value: bundled,verify
        - name: KONG_LUA_PACKAGE_PATH
          value: "/opt/?.lua;;"
        volumeMounts:
        - name: kong-plugin-verify
          mountPath: /opt/kong/plugins/verify
      volumes:
      - name: kong-plugin-verify
        configMap:
          name: kong-plugin-verify-cm

部署 Kong ingress controller

(1)创建部署目录

[root@k8s-master verify]# mkdir verify_kustomization

(2)放置Kong ingress controller原始yaml文件以及补丁文件

[root@k8s-master kong-install]# tree verify_kustomization/
verify_kustomization/
├── kong-ingress-controller.yaml
└── kong-plugin-patch-verify.yaml

0 directories, 2 files

(3)编写kustomization.yaml

resources:
    - kong-ingress-controller.yaml
patchesStrategicMerge:
    - kong-plugin-patch-verify.yaml

(4)执行部署命令

[root@k8s-master verify_kustomization]# kubectl apply -k .
namespace/kong unchanged
Warning: apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.k8s.io/v1 CustomResourceDefinition
customresourcedefinition.apiextensions.k8s.io/kongclusterplugins.configuration.konghq.com unchanged
customresourcedefinition.apiextensions.k8s.io/kongconsumers.configuration.konghq.com unchanged
customresourcedefinition.apiextensions.k8s.io/kongcredentials.configuration.konghq.com unchanged
customresourcedefinition.apiextensions.k8s.io/kongingresses.configuration.konghq.com unchanged
customresourcedefinition.apiextensions.k8s.io/kongplugins.configuration.konghq.com unchanged
customresourcedefinition.apiextensions.k8s.io/tcpingresses.configuration.konghq.com configured
serviceaccount/kong-serviceaccount unchanged
Warning: rbac.authorization.k8s.io/v1beta1 ClusterRole is deprecated in v1.17+, unavailable in v1.22+; use rbac.authorization.k8s.io/v1 ClusterRole
clusterrole.rbac.authorization.k8s.io/kong-ingress-clusterrole unchanged
Warning: rbac.authorization.k8s.io/v1beta1 ClusterRoleBinding is deprecated in v1.17+, unavailable in v1.22+; use rbac.authorization.k8s.io/v1 ClusterRoleBinding
clusterrolebinding.rbac.authorization.k8s.io/kong-ingress-clusterrole-nisa-binding unchanged
service/kong-proxy unchanged
service/kong-validation-webhook unchanged
deployment.apps/ingress-kong configured

(5)验证结果

[root@k8s-master verify_kustomization]# curl http://10.44.0.3:8001/plugins/enabled | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   507  100   507    0     0   128k      0 --:--:-- --:--:-- --:--:--  165k
{
  "enabled_plugins": [
    "grpc-web",
    "correlation-id",
    "pre-function",
    "cors",
    "rate-limiting",
    # 可以看到插件已经被启用了
    "verify",
    "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",
    "session",
    "datadog",
    "tcp-log",
    "prometheus",
    "post-function",
    "ldap-auth",
    "acl",
    "grpc-gateway",
    "file-log",
    "syslog",
    "udp-log",
    "response-ratelimiting",
    "aws-lambda",
    "bot-detection",
    "acme",
    "request-termination"
  ]
}

使用插件


创建插件资源

[root@k8s-master kong-install]# cat kong-plugin-verify.yaml 
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: kong-plugin-verify
config:
  header_name: "test-header"
  header_value: "test-body"
plugin: verify

[root@k8s-master kong-install]# kubectl apply -f kong-plugin-verify.yaml

应用到ingress中

[root@k8s-master kong-install]# kubectl get ingress
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
NAME   CLASS    HOSTS   ADDRESS   PORTS   AGE
demo   <none>   *                 80      122m
[root@k8s-master kong-install]# kubectl edit ingress demo
[root@k8s-master kong-install]# kubectl get ingress -o yaml
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
apiVersion: v1
items:
- apiVersion: extensions/v1beta1
  kind: Ingress
  metadata:
    annotations:
      konghq.com/plugins: kong-plugin-verify # 添加插件
      konghq.com/strip-path: "true"
      kubectl.kubernetes.io/last-applied-configuration: |
        {"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"annotations":{"konghq.com/strip-path":"true","kubernetes.io/ingress.class":"kong"},"name":"demo","namespace":"default"},"spec":{"rules":[{"http":{"paths":[{"backend":{"serviceName":"echo","servicePort":80},"path":"/bar"}]}}]}}
      kubernetes.io/ingress.class: kong
    creationTimestamp: "2020-09-16T18:06:21Z"
    generation: 1
    managedFields:
    - apiVersion: extensions/v1beta1
      fieldsType: FieldsV1
      fieldsV1:
        f:metadata:
          f:annotations:
            .: {}
            f:konghq.com/strip-path: {}
            f:kubectl.kubernetes.io/last-applied-configuration: {}
            f:kubernetes.io/ingress.class: {}
        f:spec:
          f:rules: {}
      manager: kubectl-client-side-apply
      operation: Update
      time: "2020-09-16T18:06:21Z"
    - apiVersion: extensions/v1beta1
      fieldsType: FieldsV1
      fieldsV1:
        f:metadata:
          f:annotations:
            f:konghq.com/plugins: {}
      manager: kubectl-edit
      operation: Update
      time: "2020-09-16T18:23:53Z"
    name: demo
    namespace: default
    resourceVersion: "1328022"
    selfLink: /apis/extensions/v1beta1/namespaces/default/ingresses/demo
    uid: 012ed881-cece-4a84-9f43-4668b4a99c4a
  spec:
    rules:
    - http:
        paths:
        - backend:
            serviceName: echo
            servicePort: 80
          path: /bar
          pathType: ImplementationSpecific
  status:
    loadBalancer: {}
kind: List
metadata:
  resourceVersion: ""
  selfLink: ""

测试插件

[root@k8s-master kong-install]# curl http://10.1.221.255/bar -i
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Date: Wed, 16 Sep 2020 18:24:16 GMT
Server: echoserver
verify: tianxiaoyong
X-Kong-Upstream-Latency: 1
X-Kong-Proxy-Latency: 1
Via: kong/2.1.3



Hostname: echo-8467949b65-tlh68

Pod Information:
        node name:      k8s-node-1
        pod name:       echo-8467949b65-tlh68
        pod namespace:  default
        pod IP: 10.44.0.2

Server values:
        server_version=nginx: 1.13.3 - lua: 10008

Request Information:
        client_address=10.44.0.3
        method=GET
        real path=/
        query=
        request_version=1.1
        request_scheme=http
        request_uri=http://10.1.221.255:8080/

Request Headers:
        accept=*/*
        connection=keep-alive
        host=10.1.221.255
        test-header=test-body
        user-agent=curl/7.29.0
        x-forwarded-for=10.32.0.1
        x-forwarded-host=10.1.221.255
        x-forwarded-port=8000
        x-forwarded-prefix=/bar
        x-forwarded-proto=http
        x-real-ip=10.32.0.1

Request Body:
        -no body in request-
[root@k8s-master kong-install]# kubectl logs -f ingress-kong-7b76fcccc4-xp8kh -n kong -c proxy

...

2020/09/16 19:03:54 [notice] 22#0: *14586 +------------------------------------------------------------------------------------------------------------------------+, client: 10.32.0.1, server: kong, request: "GET /bar HTTP/1.1", host: "10.1.221.255"
2020/09/16 19:03:54 [notice] 22#0: *14586 |[kong] handler.lua:?:17 {                                                                                               |, client: 10.32.0.1, server: kong, request: "GET /bar HTTP/1.1", host: "10.1.221.255"
2020/09/16 19:03:54 [notice] 22#0: *14586 |  __key__ = "plugins:verify:d7300db1-14eb-5a09-b594-2db904ed8eca::::0dc6f45b-8f8d-40d2-a504-473544ee190b",              |, client: 10.32.0.1, server: kong, request: "GET /bar HTTP/1.1", host: "10.1.221.255"
2020/09/16 19:03:54 [notice] 22#0: *14586 |  __seq__ = 2,                                                                                                          |, client: 10.32.0.1, server: kong, request: "GET /bar HTTP/1.1", host: "10.1.221.255"
2020/09/16 19:03:54 [notice] 22#0: *14586 |  header_name = "test-header",                                                                                          |, client: 10.32.0.1, server: kong, request: "GET /bar HTTP/1.1", host: "10.1.221.255"
2020/09/16 19:03:54 [notice] 22#0: *14586 |  header_value = "test-body",                                                                                           |, client: 10.32.0.1, server: kong, request: "GET /bar HTTP/1.1", host: "10.1.221.255"
2020/09/16 19:03:54 [notice] 22#0: *14586 |  route_id = "d7300db1-14eb-5a09-b594-2db904ed8eca"                                                                     |, client: 10.32.0.1, server: kong, request: "GET /bar HTTP/1.1", host: "10.1.221.255"
2020/09/16 19:03:54 [notice] 22#0: *14586 |}                                                                                                                       |, client: 10.32.0.1, server: kong, request: "GET /bar HTTP/1.1", host: "10.1.221.255"
2020/09/16 19:03:54 [notice] 22#0: *14586 +------------------------------------------------------------------------------------------------------------------------+, client: 10.32.0.1, server: kong, request: "GET /bar HTTP/1.1", host: "10.1.221.255"
10.32.0.1 - - [16/Sep/2020:19:03:54 +0000] "GET /bar HTTP/1.1" 200 692 "-" "curl/7.29.0"

参考链接


最后修改:2021 年 08 月 05 日 09 : 45 AM
如果觉得我的文章对你有用,请随意赞赏