apisix基于端口的SSL路由

插件说明

         基于radixtree_sni路由插件,使用port字段而非sni进行路由选择。

         radixtree_port依赖的SSL属性如下:

名字

可选项

类型

说明

示例

cert

必需

证书

https 证书

 

key

必需

私钥

https 证书私钥

 

port

必需

匹配规则

需要匹配的端口

 

certs

可选

证书字符串数组

当你想给同一个域名配置多个证书时,除了第一个证书需要通过 cert 传递外,剩下的证书可以通过该参数传递上来

 

keys

可选

私钥字符串数组

certs 对应的证书私钥,注意要跟 certs 一一对应

 

client.ca

可选

证书

设置将用于客户端证书校验的 CA 证书。该特性需要 OpenResty 1.19+

 

client.depth

可选

辅助

设置客户端证书校验的深度,默认为 1。该特性需要 OpenResty 1.19+

 

labels

可选

匹配规则

标识附加属性的键值对

{"version":"v2","build":"16","env":"production"}

 

安装流程

复制插件到router目录

cd /usr/local/apisix/apisix/ssl/router
vi ./radixtree_port.lua    #键入插件代码

修改SSL模板配置

cd /usr/local/apisix
vi ./schema_def.lua    #修改_M.SSL配置
_M.ssl = {
    type = "object",
    properties = {
        id = id_schema,
        cert = certificate_scheme,
        key = private_key_schema,
        certs = {
            type = "array",
            items = certificate_scheme,
        },
        keys = {
            type = "array",
            items = private_key_schema,
        },
        port = {
            type = "integer"
        },   --changed
        client = {
            type = "object",
            properties = {
                ca = certificate_scheme,
                depth = {
                    type = "integer",
                    minimum = 0,
                    default = 1,
                },
            },
            required = {"ca"},
        },
        exptime = {
            type = "integer",
            minimum = 1588262400,  -- 2020/5/1 0:0:0
        },
        labels = labels_def,
        status = {
            description = "ssl status, 1 to enable, 0 to disable",
            type = "integer",
            enum = {1, 0},
            default = 1
        },
        validity_end = timestamp_def,
        validity_start = timestamp_def,
        create_time = timestamp_def,
        update_time = timestamp_def
    },
    required = {"port", "key", "cert"},
    additionalProperties = false,
}

修改路由配置

cd /usr/local/apisix/conf
vi ./config-default.yaml    #修改路由配置

删除或注释ssl: 'radixtree_sni'字段,新增ssl: 'radixtree_port'以选择路由插件

……
……
router:
    http: 'radixtree_uri' 
  # ssl: 'radixtree_sni' 
ssl: 'radixtree_port'
……
……

插件代码

--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements.  See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License.  You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
local get_request      = require("resty.core.base").get_request
local router_new       = require("apisix.utils.router").new
local core             = require("apisix.core")
local apisix_ssl       = require("apisix.ssl")
local ngx_ssl          = require("ngx.ssl")
local config_util      = require("apisix.core.config_util")
local ipairs           = ipairs
local type             = type
local error            = error
local str_find         = core.string.find
local str_gsub         = string.gsub
local ssl_certificates
local radixtree_router
local radixtree_router_ver


local _M = {
    version = 0.1,
    server_name = ngx_ssl.server_name,
}


local function create_router(ssl_items) --changed
    local ssl_items = ssl_items or {}

    local route_items = core.table.new(#ssl_items, 0)
    local idx = 0

    for _, ssl in config_util.iterate_values(ssl_items) do
        if ssl.value ~= nil and
            (ssl.value.status == nil or ssl.value.status == 1) then  -- compatible with old version
            
            local labels_port = tostring(ssl.value.port)
            idx = idx + 1
            route_items[idx] = {
                paths = labels_port,
                handler = function (api_ctx)
                    if not api_ctx then
                        return
                    end
                    api_ctx.matched_ssl = ssl
                end
            }
        end
    end

    core.log.info("route items: ", core.json.delay_encode(route_items, true))
    -- for testing
    if #route_items > 1 then
        core.log.info("we have more than 1 ssl certs now")
    end
    local router, err = router_new(route_items)
    if not router then
        return nil, err
    end

    return router
end


local function set_pem_ssl_key(port, cert, pkey) --changed
    local r = get_request()
    if r == nil then
        return false, "no request found"
    end

    local parsed_cert, err = apisix_ssl.fetch_cert(port, cert)
    if not parsed_cert then
        return false, "failed to parse PEM cert: " .. err
    end

    local ok, err = ngx_ssl.set_cert(parsed_cert)
    if not ok then
        return false, "failed to set PEM cert: " .. err
    end

    local parsed_pkey, err = apisix_ssl.fetch_pkey(port, pkey)
    if not parsed_cert then
        return false, "failed to parse PEM priv key: " .. err
    end

    ok, err = ngx_ssl.set_priv_key(parsed_pkey)
    if not ok then
        return false, "failed to set PEM priv key: " .. err
    end

    return true
end


function _M.match_and_set(api_ctx)
    local err
    if not radixtree_router or
       radixtree_router_ver ~= ssl_certificates.conf_version then
        radixtree_router, err = create_router(ssl_certificates.values)
        if not radixtree_router then
            return false, "failed to create radixtree router: " .. err
        end
        radixtree_router_ver = ssl_certificates.conf_version
    end

    local port = tostring(ngx_ssl.server_port())    --changed
    local ok = radixtree_router:dispatch(port, nil, api_ctx)

    if not ok then
        core.log.error("failed to find any SSL certificate by Port: ", port)    --changed
        return false
    end

    local matched_ssl = api_ctx.matched_ssl
    core.log.info("debug - matched: ", core.json.delay_encode(matched_ssl, true))

    ngx_ssl.clear_certs()

    ok, err = set_pem_ssl_key(port, matched_ssl.value.cert,
                              matched_ssl.value.key)    --changed
    if not ok then
        return false, err
    end

    -- multiple certificates support.
    if matched_ssl.value.certs then
        for i = 1, #matched_ssl.value.certs do
            local cert = matched_ssl.value.certs[i]
            local key = matched_ssl.value.keys[i]

            ok, err = set_pem_ssl_key(port, cert, key)  --changed
            if not ok then
                return false, err
            end
        end
    end

    if matched_ssl.value.client then
        local ca_cert = matched_ssl.value.client.ca
        local depth = matched_ssl.value.client.depth
        if apisix_ssl.support_client_verification() then
            local parsed_cert, err = apisix_ssl.fetch_cert(port, ca_cert)    --changed
            if not parsed_cert then
                return false, "failed to parse client cert: " .. err
            end

            local ok, err = ngx_ssl.verify_client(parsed_cert, depth)
            if not ok then
                return false, err
            end

            api_ctx.ssl_client_verified = true
        end
    end

    return true
end


function _M.ssls()
    if not ssl_certificates then
        return nil, nil
    end

    return ssl_certificates.values, ssl_certificates.conf_version
end


function _M.init_worker()
    local err
    ssl_certificates, err = core.config.new("/ssl", {
        automatic = true,
        item_schema = core.schema.ssl,
        checker = function (item, schema_type)
            return apisix_ssl.check_ssl_conf(true, item)
        end,
    })
    if not ssl_certificates then
        error("failed to create etcd instance for fetching ssl certificates: "
              .. err)
    end
end


return _M

 

posted @ 2021-08-13 11:37  午默  阅读(2302)  评论(0编辑  收藏  举报