cn_wumo
文章4
标签4
分类4
apisix基于端口的SSL路由

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目录

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

修改SSL模板配置

1
2
cd /usr/local/apisix
vi ./schema_def.lua #修改_M.SSL配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
_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,
}

修改路由配置

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

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

1
2
3
4
5
6
7
8
……
……
router:
http: 'radixtree_uri'
# ssl: 'radixtree_sni'
ssl: 'radixtree_port'
……
……

插件代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
--
-- 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
apisix基于username和password的JWT验证插件

apisix基于username和password的JWT验证插件

插件说明

基于jwt-auth插件,新增了password字段和相应的逻辑判断。

jwt-diy的属性表如下:

名称 类型 必选项 默认值 有效值 描述
key string 必须 不同的 consumer 对象应有不同的值,它应当是唯一的。不同 consumer 使用了相同的 key ,将会出现请求匹配异常。
password string 必须 Key对应的口令,唯有key和password相匹配才会返回token
secret string 可选 加密秘钥。如果您未指定,后台将会自动帮您生成。
public_key string 可选 RSA 公钥, algorithm 属性选择 RS256 算法时必填
private_key string 可选 RSA 私钥, algorithm 属性选择 RS256 算法时必填
algorithm string 可选 “HS256” [“HS256”, “HS512”, “RS256”] 加密算法
exp integer 可选 86400 [1,…] token 的超时时间
base64_secret boolean 可选 false 密钥是否为 base64 编码

安装流程

复制插件到plugins目录

1
2
cd /usr/local/apisix/apisix/plugins
vi ./jwt-diy.lua #键入插件代码

修改默认配置

1
2
cd /usr/local/apisix/conf
vi ./config-default.yaml #修改默认配置

键入配置信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
……
……
plugins: # plugin list (sorted by priority)
- client-control # priority: 22000
- ext-plugin-pre-req # priority: 12000
- zipkin # priority: 11011
- request-id # priority: 11010
- fault-injection # priority: 11000
- serverless-pre-function # priority: 10000
- batch-requests # priority: 4010
- cors # priority: 4000
- ip-restriction # priority: 3000
- referer-restriction # priority: 2990
- uri-blocker # priority: 2900
- request-validation # priority: 2800
- openid-connect # priority: 2599
- wolf-rbac # priority: 2555
- hmac-auth # priority: 2530
- basic-auth # priority: 2520
- jwt-auth # priority: 2510
- key-auth # priority: 2500
- consumer-restriction # priority: 2400
- authz-keycloak # priority: 2000
#- error-log-logger # priority: 1091
- proxy-mirror # priority: 1010
- proxy-cache # priority: 1009
- proxy-rewrite # priority: 1008
- api-breaker # priority: 1005
- limit-conn # priority: 1003
- limit-count # priority: 1002
- limit-req # priority: 1001
#- node-status # priority: 1000
- server-info # priority: 990
- traffic-split # priority: 966
- redirect # priority: 900
- response-rewrite # priority: 899
#- dubbo-proxy # priority: 507
- grpc-transcode # priority: 506
- prometheus # priority: 500
- echo # priority: 412
- http-logger # priority: 410
- sls-logger # priority: 406
- tcp-logger # priority: 405
- kafka-logger # priority: 403
- syslog # priority: 401
- udp-logger # priority: 400
#- log-rotate # priority: 100
# <- recommend to use priority (0, 100) for your custom plugins
#键入jwt-diy插件的文件名
- jwt-diy # priority: 1
- example-plugin # priority: 0
#- skywalking # priority: -1100
- serverless-post-function # priority: -2000
- ext-plugin-post-req # priority: -3000

stream_plugins: # sorted by priority
- mqtt-proxy # priority: 1000
# <- recommend to use priority (0, 100) for your custom plugins
……
……

如何启用

创建一个 consumer 对象,指定RSA算法,并设置插件 jwt-diy的值,配置公钥和私钥。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
curl http://0.0.0.0:9080/apisix/admin/consumers -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"username": "user",
"plugins": {
"jwt-diy": {
"key": user-key,
"password": password,
"public_key": "-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAM++1NAk1SnpjHgglXDWypaFdff07ymE
mI9AKYHgRNwutnIDN8CD2Pm4uHPtGCkkV1GAJZJkmOCsRULwGh51NdECAwEAAQ==
-----END PUBLIC KEY-----",
"private_key": "-----BEGIN PRIVATE KEY-----
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAz77U0CTVKemMeCCV
cNbKloV19/TvKYSYj0ApgeBE3C62cgM3wIPY+bi4c+0YKSRXUYAlkmSY4KxFQvAa
HnU10QIDAQABAkB5CG8oTS072+uQ2Tr3oMwq4dqW+caU48GWRAVqu2Si+i7k3Igi
tqaz/xAs2iXTdj/W1F8tNmw2xsKBILN6LpGhAiEA9aHWC7FkRjPYrBDv5zvvR8pc
+CspzOHKrgyiBmKWwQ0CIQDYg5y+24S5jHv48Yr2/KeKug09S9Y60RhED5IEzZ9u
1QIhAMHKOa4l+R+t3d76ydscHQ79p9WfcC4VYatpihcRhzCtAiEA142AGcs2QfwI
2Hiw3t/+dPBxidrcd0YAIJJXzwxfc9kCIHVytvdYljt1letwDHCnloa0dQmhZUvJ
+IEib4YXcSPh
-----END PRIVATE KEY-----",
"algorithm": "RS256"
}
}
}'

创建Route或Service对象,开启jwt-diy插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"methods": ["GET"],
"uri": "/index.html",
"plugins": {
"jwt-diy": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpunit.sourceforge.net": 1
},
"scheme": "http"
}
}'

获取token

1
2
3
4
5
6
7
8
9
10
curl http://0.0.0.0:9080/apisix/plugin/jwt/sign?key=user-key\&password=password –i

HTTP/1.1 200 OK
Date: Wed, 11 Aug 2021 02:42:19 GMT
Content-Type: text/plain; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Server: APISIX/2.7

eyJhbGciOiJSUzI1NiIsIng1YyI6WyItLS0tLUJFR0lOIFBVQkxJQyBLRVktLS0tLVxuTUZ3d0RRWUpLb1pJaHZjTkFRRUJCUUFEU3dBd1NBSkJBTSsrMU5BazFTbnBqSGdnbFhEV3lwYUZkZmYwN3ltRVxubUk5QUtZSGdSTnd1dG5JRE44Q0QyUG00dUhQdEdDa2tWMUdBSlpKa21PQ3NSVUx3R2g1MU5kRUNBd0VBQVE9PVxuLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tIl0sInR5cCI6IkpXVCJ9.eyJrZXkiOiJ1c2VyLWtleSIsImV4cCI6MTYyODczNjEzOX0.JcWTONIumTfwZjfsx0kxNGIA_DpPCXmhIf9EWQxGG7y_UL6s_4eFvV-iAeqIt8yshR12DcaR6R9jMpCoCiYB3A

插件代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
--
-- 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 core = require("apisix.core")
local jwt = require("resty.jwt")
local ck = require("resty.cookie")
local consumer_mod = require("apisix.consumer")
local resty_random = require("resty.random")

local ngx_encode_base64 = ngx.encode_base64
local ngx_decode_base64 = ngx.decode_base64
local ipairs = ipairs
local ngx = ngx
local ngx_time = ngx.time
local sub_str = string.sub
local plugin_name = "jwt-diy"
local pcall = pcall


local lrucache = core.lrucache.new({
type = "plugin",
})

local schema = {
type = "object",
additionalProperties = false,
properties = {},
}

local consumer_schema = {
type = "object",
-- can't use additionalProperties with dependencies
-- additionalProperties = false,
properties = {
key = {type = "string"},
secret = {type = "string"},
password = {type = "string"}, --changed
algorithm = {
type = "string",
enum = {"HS256", "HS512", "RS256"},
default = "HS256"
},
exp = {type = "integer", minimum = 1, default = 86400},
base64_secret = {
type = "boolean",
default = false
}
},
dependencies = {
algorithm = {
oneOf = {
{
properties = {
algorithm = {
enum = {"HS256", "HS512"},
default = "HS256"
},
},
},
{
properties = {
public_key = {type = "string"},
private_key= {type = "string"},
algorithm = {
enum = {"RS256"},
},
},
required = {"public_key", "private_key"},
}
}
}
},
required = {"key","password"}, --changed
}


local _M = {
version = 0.1,
priority = 1,
type = 'auth',
name = plugin_name,
schema = schema,
consumer_schema = consumer_schema
}


local create_consume_cache
do
local consumer_names = {}

function create_consume_cache(consumers)
core.table.clear(consumer_names)

for _, consumer in ipairs(consumers.nodes) do
core.log.info("consumer node: ", core.json.delay_encode(consumer))
consumer_names[consumer.auth_conf.key] = consumer
end

return consumer_names
end

end -- do


function _M.check_schema(conf, schema_type)
core.log.info("input conf: ", core.json.delay_encode(conf))

local ok, err
if schema_type == core.schema.TYPE_CONSUMER then
ok, err = core.schema.check(consumer_schema, conf)
else
ok, err = core.schema.check(schema, conf)
end

if not ok then
return false, err
end

if schema_type == core.schema.TYPE_CONSUMER then
if conf.algorithm ~= "RS256" and not conf.secret then
conf.secret = ngx_encode_base64(resty_random.bytes(32, true))
elseif conf.base64_secret then
if ngx_decode_base64(conf.secret) == nil then
return false, "base64_secret required but the secret is not in base64 format"
end
end

if conf.algorithm == "RS256" then
if not conf.public_key then
return false, "missing valid public key"
end
if not conf.private_key then
return false, "missing valid private key"
end
end
end

return true
end


local function fetch_jwt_token(ctx)
local token = core.request.header(ctx, "authorization")
if token then
local prefix = sub_str(token, 1, 7)
if prefix == 'Bearer ' or prefix == 'bearer ' then
return sub_str(token, 8)
end

return token
end

token = ctx.var.arg_jwt
if token then
return token
end

local cookie, err = ck:new()
if not cookie then
return nil, err
end

local val, err = cookie:get("jwt")
return val, err
end


local function get_secret(conf)
if conf.base64_secret then
return ngx_decode_base64(conf.secret)
end

return conf.secret
end


local function get_real_payload(key, auth_conf, payload)
local real_payload = {
key = key,
exp = ngx_time() + auth_conf.exp
}
if payload then
local extra_payload = core.json.decode(payload)
core.table.merge(real_payload, extra_payload)
end
return real_payload
end


local function sign_jwt_with_HS(key, auth_conf, payload)
local auth_secret = get_secret(auth_conf)
local ok, jwt_token = pcall(jwt.sign, _M,
auth_secret,
{
header = {
typ = "JWT",
alg = auth_conf.algorithm
},
payload = get_real_payload(key, auth_conf, payload)
}
)
if not ok then
core.log.warn("failed to sign jwt, err: ", jwt_token.reason)
core.response.exit(500, "failed to sign jwt")
end
return jwt_token
end


local function sign_jwt_with_RS256(key, auth_conf, payload)
local ok, jwt_token = pcall(jwt.sign, _M,
auth_conf.private_key,
{
header = {
typ = "JWT",
alg = auth_conf.algorithm,
x5c = {
auth_conf.public_key,
}
},
payload = get_real_payload(key, auth_conf, payload)
}
)
if not ok then
core.log.warn("failed to sign jwt, err: ", jwt_token.reason)
core.response.exit(500, "failed to sign jwt")
end
return jwt_token
end


local function algorithm_handler(consumer)
if not consumer.auth_conf.algorithm or consumer.auth_conf.algorithm == "HS256"
or consumer.auth_conf.algorithm == "HS512" then
return sign_jwt_with_HS, get_secret(consumer.auth_conf)
elseif consumer.auth_conf.algorithm == "RS256" then
return sign_jwt_with_RS256, consumer.auth_conf.public_key
end
end


function _M.rewrite(conf, ctx)
local jwt_token, err = fetch_jwt_token(ctx)
if not jwt_token then
if err and err:sub(1, #"no cookie") ~= "no cookie" then
core.log.error("failed to fetch JWT token: ", err)
end

return 401, {message = "Missing JWT token in request"}
end

local jwt_obj = jwt:load_jwt(jwt_token)
core.log.info("jwt object: ", core.json.delay_encode(jwt_obj))
if not jwt_obj.valid then
return 401, {message = jwt_obj.reason}
end

local user_key = jwt_obj.payload and jwt_obj.payload.key
if not user_key then
return 401, {message = "missing user key in JWT token"}
end

local consumer_conf = consumer_mod.plugin(plugin_name)
if not consumer_conf then
return 401, {message = "Missing related consumer"}
end

local consumers = lrucache("consumers_key", consumer_conf.conf_version,
create_consume_cache, consumer_conf)

local consumer = consumers[user_key]
if not consumer then
return 401, {message = "Invalid user key in JWT token"}
end
core.log.info("consumer: ", core.json.delay_encode(consumer))

local _, auth_secret = algorithm_handler(consumer)
jwt_obj = jwt:verify_jwt_obj(auth_secret, jwt_obj)
core.log.info("jwt object: ", core.json.delay_encode(jwt_obj))

if not jwt_obj.verified then
return 401, {message = jwt_obj.reason}
end

consumer_mod.attach_consumer(ctx, consumer, consumer_conf)
core.log.info("hit jwt-auth rewrite")
end

local function gen_token()
local args = ngx.req.get_uri_args()
if not args or not args.key or not args.password then --changed
return core.response.exit(400)
end

local key = args.key
local payload = args.payload
local password = args.password --changed
if payload then
payload = ngx.unescape_uri(payload)
end

local consumer_conf = consumer_mod.plugin(plugin_name)
if not consumer_conf then
return core.response.exit(404)
end

local consumers = lrucache("consumers_key", consumer_conf.conf_version,
create_consume_cache, consumer_conf)

core.log.info("consumers: ", core.json.delay_encode(consumers))
local consumer = consumers[key]

if ((not consumer) or (password ~= consumer.auth_conf.password)) then --changed
return core.response.exit(404)
end

core.log.info("consumer: ", core.json.delay_encode(consumer))

local sign_handler, _ = algorithm_handler(consumer)
local jwt_token = sign_handler(key, consumer.auth_conf, payload)
if jwt_token then
return core.response.exit(200, jwt_token)
end

return core.response.exit(404)
end

function _M.api()
return {
{
methods = {"GET"},
uri = "/apisix/plugin/jwt/sign",
handler = gen_token,
}
}
end

return _M
Docker环境下的etcd集群的搭建

Docker环境下的etcd集群的搭建

基于centos容器运行etcd集群,默认2379端口是客户监听端口,2380是集群监听端口

centos下的单节点etcd运行可见
http://cn-wumo.top/2021/09-05-CentOS下的etcd的搭建

1
2
3
docker run –name etcd_1 –p 12379:2379 –p 12380:2380 –it centos /bin/bash
docker run –name etcd_2 –p 22379:2379 –p 22380:2380 –it centos /bin/bash
docker run –name etcd_3 –p 32379:2379 –p 32380:2380 –it centos /bin/bash

不带ssl证书的集群搭建,三个容器都要启动

1
2
3
4
5
6
7
8
./etcd -name etcd_1 \
-advertise-client-urls https://0.0.0.0:2379 \
-listen-client-urls https://0.0.0.0:2379 \
-listen-peer-urls https://0.0.0.0:2380 \
-initial-advertise-peer-urls https://0.0.0.0:12380 \
-initial-cluster-token etcd-cluster \
-initial-cluster "etcd_1=http://0.0.0.0:12380,etcd_2=http://0.0.0.0:22380,etcd_3=http://0.0.0.0:32380" \
-initial-cluster-state new

带ssl证书的集群搭建,三个容器都要启动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
./etcd -name etcd_1 \
--auto-tls=true \
--client-cert-auth=true \
--cert-file=/ssl/server.pem \
--key-file=/ssl/server-key.pem \
--trusted-ca-file=/ssl/ca.pem \
--peer-auto-tls=true \
--peer-cert-file=/ssl/peer.pem \
--peer-key-file=/ssl/peer-key.pem \
--peer-client-cert-auth=true \
--peer-trusted-ca-file=/ssl/ca.pem \
-advertise-client-urls https://0.0.0.0:2379 \
-listen-client-urls https://0.0.0.0:2379 \
-listen-peer-urls https://0.0.0.0:2380 \
-initial-advertise-peer-urls https://0.0.0.0:12380 \
-initial-cluster-token etcd-cluster \
-initial-cluster "etcd_1=https://0.0.0.0:12380,etcd_2=https://0.0.0.0:22380,etcd_3=https://0.0.0.0:32380" \
-initial-cluster-state new

注意-initial-advertise-peer-urls字段,-initial-cluster字段填写宿主机的ip地址

不带证书检查集群的状态

1
./etcdctl endpoint status

带证书检查集群的状态

1
2
3
4
5
6
./etcdctl \
--cacert=/ssl/ca.pem \
--cert=/ssl/server.pem \
--key=/ssl/server-key.pem \
--endpoints https://127.0.0.1:2379 \
endpoint status

不带证书集群新增etcd节点(先添加,后启动)

1
./etcdctl --endpoints http://0.0.0.0:12380 member add etcd_4 http://0.0.0.0:42380

带证书集群新增etcd节点(先添加,后启动)

1
2
3
4
5
./etcdctl \
--cacert=./ca.pem \
--cert=./server.pem \
--key=./server-key.pem \
--endpoints http://0.0.0.0:12380 member add etcd_4 http://0.0.0.0:42380

不带证书启动etcd_4节点

1
2
3
4
5
6
7
8
./etcd -name etcd_4 \
-advertise-client-urls https://0.0.0.0:2379 \
-listen-client-urls https://0.0.0.0:2379 \
-listen-peer-urls https://0.0.0.0:2380 \
-initial-advertise-peer-urls https://0.0.0.0:42380 \
-initial-cluster-token etcd-cluster \
-initial-cluster "etcd_1=https://0.0.0.0:12380,etcd_2=https://0.0.0.0:22380,etcd_3=https://0.0.0.0:32380,etcd_4=https://0.0.0.0:42380" \
-initial-cluster-state new

带证书同理

CentOS下的etcd的搭建

CentOS下的etcd的搭建

首先是从官网下载etcd所需的工具

1
yum install wget -y

使用wget下载压缩文件

1
wget https://github.com/etcd-io/etcd/releases/download/v3.5.0/etcd-v3.5.0-linux-amd64.tar.gz

更多的版本可以访问

1
https://github.com/etcd-io/etcd/releases

解压当前目录下的压缩文件,删除压缩文件包

1
2
3
wget https://github.com/etcd-io/etcd/releases/download/v3.5.0/etcd-v3.5.0-linux-amd64.tar.gz
tar -xvf etcd-v3.5.0-linux-amd64.tar.gz
rm -rf etcd-v3.5.0-linux-amd64.tar.gz

启动etcd单节点

1
2
3
4
./etcd -name etcd1 \
-advertise-client-urls http://0.0.0.0:2379 \
-listen-client-urls http://0.0.0.0:2379 \
-initial-advertise-peer-urls http://0.0.0.0:2380

测试节点状态

1
./etcdctl endpoint status

返回127.0.0.1:2379, 1c70f9bbb41018f, 3.5.0, 20 kB, true, false, 2, 4, 4, 表明etcd程序正常运行