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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM