client-mtls.t 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  1. #
  2. # Licensed to the Apache Software Foundation (ASF) under one or more
  3. # contributor license agreements. See the NOTICE file distributed with
  4. # this work for additional information regarding copyright ownership.
  5. # The ASF licenses this file to You under the Apache License, Version 2.0
  6. # (the "License"); you may not use this file except in compliance with
  7. # the License. You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. #
  17. use t::APISIX;
  18. my $nginx_binary = $ENV{'TEST_NGINX_BINARY'} || 'nginx';
  19. my $version = eval { `$nginx_binary -V 2>&1` };
  20. if ($version !~ m/\/apisix-nginx-module/) {
  21. plan(skip_all => "apisix-nginx-module not installed");
  22. } else {
  23. plan('no_plan');
  24. }
  25. repeat_each(1);
  26. log_level('info');
  27. no_root_location();
  28. no_shuffle();
  29. add_block_preprocessor(sub {
  30. my ($block) = @_;
  31. });
  32. run_tests();
  33. __DATA__
  34. === TEST 1: bad client certificate
  35. --- config
  36. location /t {
  37. content_by_lua_block {
  38. local t = require("lib.test_admin")
  39. local json = require("toolkit.json")
  40. local ssl_cert = t.read_file("t/certs/mtls_client.crt")
  41. local ssl_key = t.read_file("t/certs/mtls_client.key")
  42. local data = {
  43. cert = ssl_cert,
  44. key = ssl_key,
  45. sni = "test.com",
  46. client = {
  47. ca = ("test.com"):rep(128),
  48. }
  49. }
  50. local code, body = t.test('/apisix/admin/ssls/1',
  51. ngx.HTTP_PUT,
  52. json.encode(data)
  53. )
  54. if code >= 300 then
  55. ngx.status = code
  56. end
  57. ngx.print(body)
  58. }
  59. }
  60. --- request
  61. GET /t
  62. --- error_code: 400
  63. --- response_body
  64. {"error_msg":"failed to validate client_cert: failed to parse cert: PEM_read_bio_X509_AUX() failed"}
  65. === TEST 2: missing client certificate
  66. --- config
  67. location /t {
  68. content_by_lua_block {
  69. local t = require("lib.test_admin")
  70. local json = require("toolkit.json")
  71. local ssl_cert = t.read_file("t/certs/mtls_client.crt")
  72. local ssl_key = t.read_file("t/certs/mtls_client.key")
  73. local data = {
  74. cert = ssl_cert,
  75. key = ssl_key,
  76. sni = "test.com",
  77. client = {
  78. }
  79. }
  80. local code, body = t.test('/apisix/admin/ssls/1',
  81. ngx.HTTP_PUT,
  82. json.encode(data)
  83. )
  84. if code >= 300 then
  85. ngx.status = code
  86. end
  87. ngx.print(body)
  88. }
  89. }
  90. --- request
  91. GET /t
  92. --- error_code: 400
  93. --- response_body
  94. {"error_msg":"invalid configuration: property \"client\" validation failed: property \"ca\" is required"}
  95. === TEST 3: set verification
  96. --- config
  97. location /t {
  98. content_by_lua_block {
  99. local t = require("lib.test_admin")
  100. local json = require("toolkit.json")
  101. local ssl_ca_cert = t.read_file("t/certs/mtls_ca.crt")
  102. local ssl_cert = t.read_file("t/certs/mtls_client.crt")
  103. local ssl_key = t.read_file("t/certs/mtls_client.key")
  104. local data = {
  105. upstream = {
  106. scheme = "https",
  107. type = "roundrobin",
  108. nodes = {
  109. ["127.0.0.1:1994"] = 1,
  110. },
  111. tls = {
  112. client_cert = ssl_cert,
  113. client_key = ssl_key,
  114. }
  115. },
  116. plugins = {
  117. ["proxy-rewrite"] = {
  118. uri = "/hello"
  119. }
  120. },
  121. uri = "/mtls"
  122. }
  123. local code, body = t.test('/apisix/admin/routes/1',
  124. ngx.HTTP_PUT,
  125. json.encode(data)
  126. )
  127. if code >= 300 then
  128. ngx.status = code
  129. ngx.say(body)
  130. return
  131. end
  132. local data = {
  133. upstream = {
  134. type = "roundrobin",
  135. nodes = {
  136. ["127.0.0.1:1980"] = 1,
  137. },
  138. },
  139. uri = "/hello"
  140. }
  141. assert(t.test('/apisix/admin/routes/2',
  142. ngx.HTTP_PUT,
  143. json.encode(data)
  144. ))
  145. local data = {
  146. cert = ssl_cert,
  147. key = ssl_key,
  148. sni = "localhost",
  149. client = {
  150. ca = ssl_ca_cert,
  151. depth = 2,
  152. }
  153. }
  154. local code, body = t.test('/apisix/admin/ssls/1',
  155. ngx.HTTP_PUT,
  156. json.encode(data)
  157. )
  158. if code >= 300 then
  159. ngx.status = code
  160. end
  161. ngx.print(body)
  162. }
  163. }
  164. --- request
  165. GET /t
  166. === TEST 4: hit
  167. --- request
  168. GET /mtls
  169. --- more_headers
  170. Host: localhost
  171. --- response_body
  172. hello world
  173. === TEST 5: no client certificate
  174. --- config
  175. location /t {
  176. content_by_lua_block {
  177. local t = require("lib.test_admin")
  178. local json = require("toolkit.json")
  179. local data = {
  180. upstream = {
  181. scheme = "https",
  182. type = "roundrobin",
  183. nodes = {
  184. ["127.0.0.1:1994"] = 1,
  185. },
  186. },
  187. plugins = {
  188. ["proxy-rewrite"] = {
  189. uri = "/hello"
  190. }
  191. },
  192. uri = "/mtls2"
  193. }
  194. local code, body = t.test('/apisix/admin/routes/1',
  195. ngx.HTTP_PUT,
  196. json.encode(data)
  197. )
  198. if code >= 300 then
  199. ngx.status = code
  200. ngx.say(body)
  201. return
  202. end
  203. ngx.print(body)
  204. }
  205. }
  206. --- request
  207. GET /t
  208. === TEST 6: hit
  209. --- request
  210. GET /mtls2
  211. --- more_headers
  212. Host: localhost
  213. --- error_code: 502
  214. --- error_log
  215. peer did not return a certificate
  216. === TEST 7: wrong client certificate
  217. --- config
  218. location /t {
  219. content_by_lua_block {
  220. local t = require("lib.test_admin")
  221. local json = require("toolkit.json")
  222. local ssl_cert = t.read_file("t/certs/apisix.crt")
  223. local ssl_key = t.read_file("t/certs/apisix.key")
  224. local data = {
  225. upstream = {
  226. scheme = "https",
  227. type = "roundrobin",
  228. nodes = {
  229. ["127.0.0.1:1994"] = 1,
  230. },
  231. tls = {
  232. client_cert = ssl_cert,
  233. client_key = ssl_key,
  234. }
  235. },
  236. plugins = {
  237. ["proxy-rewrite"] = {
  238. uri = "/hello"
  239. }
  240. },
  241. uri = "/mtls3"
  242. }
  243. local code, body = t.test('/apisix/admin/routes/1',
  244. ngx.HTTP_PUT,
  245. json.encode(data)
  246. )
  247. if code >= 300 then
  248. ngx.status = code
  249. ngx.say(body)
  250. return
  251. end
  252. ngx.print(body)
  253. }
  254. }
  255. --- request
  256. GET /t
  257. === TEST 8: hit
  258. --- request
  259. GET /mtls3
  260. --- more_headers
  261. Host: localhost
  262. --- error_code: 502
  263. --- error_log
  264. certificate verify failed
  265. === TEST 9: set verification
  266. --- config
  267. location /t {
  268. content_by_lua_block {
  269. local t = require("lib.test_admin")
  270. local json = require("toolkit.json")
  271. local ssl_ca_cert = t.read_file("t/certs/mtls_ca.crt")
  272. local ssl_cert = t.read_file("t/certs/mtls_client.crt")
  273. local ssl_key = t.read_file("t/certs/mtls_client.key")
  274. local data = {
  275. upstream = {
  276. type = "roundrobin",
  277. nodes = {
  278. ["127.0.0.1:1980"] = 1,
  279. },
  280. },
  281. uri = "/hello"
  282. }
  283. assert(t.test('/apisix/admin/routes/1',
  284. ngx.HTTP_PUT,
  285. json.encode(data)
  286. ))
  287. local data = {
  288. cert = ssl_cert,
  289. key = ssl_key,
  290. sni = "localhost",
  291. }
  292. local code, body = t.test('/apisix/admin/ssls/1',
  293. ngx.HTTP_PUT,
  294. json.encode(data)
  295. )
  296. if code >= 300 then
  297. ngx.status = code
  298. end
  299. ngx.print(body)
  300. }
  301. }
  302. --- request
  303. GET /t
  304. === TEST 10: hit with different host which doesn't require mTLS
  305. --- exec
  306. curl --cert t/certs/mtls_client.crt --key t/certs/mtls_client.key -k https://localhost:1994/hello -H "Host: x.com"
  307. --- response_body
  308. hello world
  309. === TEST 11: set verification (2 ssl objects)
  310. --- config
  311. location /t {
  312. content_by_lua_block {
  313. local t = require("lib.test_admin")
  314. local json = require("toolkit.json")
  315. local ssl_ca_cert = t.read_file("t/certs/mtls_ca.crt")
  316. local ssl_cert = t.read_file("t/certs/mtls_client.crt")
  317. local ssl_key = t.read_file("t/certs/mtls_client.key")
  318. local data = {
  319. upstream = {
  320. type = "roundrobin",
  321. nodes = {
  322. ["127.0.0.1:1980"] = 1,
  323. },
  324. },
  325. uri = "/hello"
  326. }
  327. assert(t.test('/apisix/admin/routes/1',
  328. ngx.HTTP_PUT,
  329. json.encode(data)
  330. ))
  331. local data = {
  332. cert = ssl_cert,
  333. key = ssl_key,
  334. sni = "test.com",
  335. client = {
  336. ca = ssl_ca_cert,
  337. depth = 2,
  338. }
  339. }
  340. local code, body = t.test('/apisix/admin/ssls/1',
  341. ngx.HTTP_PUT,
  342. json.encode(data)
  343. )
  344. if code >= 300 then
  345. ngx.status = code
  346. return
  347. end
  348. local data = {
  349. cert = ssl_cert,
  350. key = ssl_key,
  351. sni = "localhost",
  352. }
  353. local code, body = t.test('/apisix/admin/ssls/2',
  354. ngx.HTTP_PUT,
  355. json.encode(data)
  356. )
  357. if code >= 300 then
  358. ngx.status = code
  359. end
  360. ngx.print(body)
  361. }
  362. }
  363. --- request
  364. GET /t
  365. === TEST 12: hit without mTLS verify, with Host requires mTLS verification
  366. --- exec
  367. curl -k https://localhost:1994/hello -H "Host: test.com"
  368. --- response_body eval
  369. qr/400 Bad Request/
  370. --- error_log
  371. client certificate verified with SNI localhost, but the host is test.com
  372. === TEST 13: set verification (2 ssl objects, both have mTLS)
  373. --- config
  374. location /t {
  375. content_by_lua_block {
  376. local t = require("lib.test_admin")
  377. local json = require("toolkit.json")
  378. local ssl_ca_cert = t.read_file("t/certs/mtls_ca.crt")
  379. local ssl_ca_cert2 = t.read_file("t/certs/apisix.crt")
  380. local ssl_cert = t.read_file("t/certs/mtls_client.crt")
  381. local ssl_key = t.read_file("t/certs/mtls_client.key")
  382. local data = {
  383. upstream = {
  384. type = "roundrobin",
  385. nodes = {
  386. ["127.0.0.1:1980"] = 1,
  387. },
  388. },
  389. uri = "/hello"
  390. }
  391. assert(t.test('/apisix/admin/routes/1',
  392. ngx.HTTP_PUT,
  393. json.encode(data)
  394. ))
  395. local data = {
  396. cert = ssl_cert,
  397. key = ssl_key,
  398. sni = "localhost",
  399. client = {
  400. ca = ssl_ca_cert,
  401. depth = 2,
  402. }
  403. }
  404. local code, body = t.test('/apisix/admin/ssls/1',
  405. ngx.HTTP_PUT,
  406. json.encode(data)
  407. )
  408. if code >= 300 then
  409. ngx.status = code
  410. return
  411. end
  412. local data = {
  413. cert = ssl_cert,
  414. key = ssl_key,
  415. sni = "test.com",
  416. client = {
  417. ca = ssl_ca_cert2,
  418. depth = 2,
  419. }
  420. }
  421. local code, body = t.test('/apisix/admin/ssls/2',
  422. ngx.HTTP_PUT,
  423. json.encode(data)
  424. )
  425. if code >= 300 then
  426. ngx.status = code
  427. end
  428. ngx.print(body)
  429. }
  430. }
  431. --- request
  432. GET /t
  433. === TEST 14: hit with mTLS verify, with Host requires different mTLS verification
  434. --- exec
  435. curl --cert t/certs/mtls_client.crt --key t/certs/mtls_client.key -k https://localhost:1994/hello -H "Host: test.com"
  436. --- response_body eval
  437. qr/400 Bad Request/
  438. --- error_log
  439. client certificate verified with SNI localhost, but the host is test.com
  440. === TEST 15: set verification (2 ssl objects, both have mTLS)
  441. --- config
  442. location /t {
  443. content_by_lua_block {
  444. local t = require("lib.test_admin")
  445. local json = require("toolkit.json")
  446. local ssl_ca_cert = t.read_file("t/certs/mtls_ca.crt")
  447. local ssl_ca_cert2 = t.read_file("t/certs/apisix.crt")
  448. local ssl_cert = t.read_file("t/certs/mtls_client.crt")
  449. local ssl_key = t.read_file("t/certs/mtls_client.key")
  450. local data = {
  451. upstream = {
  452. type = "roundrobin",
  453. nodes = {
  454. ["127.0.0.1:1980"] = 1,
  455. },
  456. },
  457. uri = "/*"
  458. }
  459. assert(t.test('/apisix/admin/routes/1',
  460. ngx.HTTP_PUT,
  461. json.encode(data)
  462. ))
  463. local data = {
  464. cert = ssl_cert,
  465. key = ssl_key,
  466. sni = "localhost",
  467. client = {
  468. ca = ssl_ca_cert,
  469. depth = 2,
  470. skip_mtls_uri_regex = {
  471. "/hello[0-9]+",
  472. }
  473. }
  474. }
  475. local code, body = t.test('/apisix/admin/ssls/1',
  476. ngx.HTTP_PUT,
  477. json.encode(data)
  478. )
  479. if code >= 300 then
  480. ngx.status = code
  481. return
  482. end
  483. local data = {
  484. cert = ssl_cert,
  485. key = ssl_key,
  486. sni = "test.com",
  487. client = {
  488. ca = ssl_ca_cert2,
  489. depth = 2,
  490. }
  491. }
  492. local code, body = t.test('/apisix/admin/ssls/2',
  493. ngx.HTTP_PUT,
  494. json.encode(data)
  495. )
  496. if code >= 300 then
  497. ngx.status = code
  498. end
  499. ngx.print(body)
  500. }
  501. }
  502. --- request
  503. GET /t
  504. === TEST 16: skip the mtls, although no client cert provided
  505. --- exec
  506. curl -k https://localhost:1994/hello1
  507. --- response_body eval
  508. qr/hello1 world/
  509. === TEST 17: skip the mtls, although with wrong client cert
  510. --- exec
  511. curl -k --cert t/certs/test2.crt --key t/certs/test2.key -k https://localhost:1994/hello1
  512. --- response_body eval
  513. qr/hello1 world/
  514. === TEST 18: mtls failed, returns 400
  515. --- exec
  516. curl -k https://localhost:1994/hello
  517. --- response_body eval
  518. qr/400 Bad Request/
  519. --- error_log
  520. client certificate was not present
  521. === TEST 19: mtls failed, wrong client cert
  522. --- exec
  523. curl --cert t/certs/test2.crt --key t/certs/test2.key -k https://localhost:1994/hello
  524. --- response_body eval
  525. qr/400 Bad Request/
  526. --- error_log
  527. client certificate verification is not passed: FAILED
  528. === TEST 20: mtls failed, at handshake phase
  529. --- exec
  530. curl -k -v --resolve "test.com:1994:127.0.0.1" https://test.com:1994/hello
  531. --- error_log
  532. peer did not return a certificate