--- title: SSL 协议 --- `APISIX` 支持 TLS 协议,还支持动态的为每一个 SNI 指定不同的 TLS 协议版本。 **为了安全考虑,APISIX 默认使用的加密套件不支持 TLSv1.1 以及更低的版本。** **如果你需要启用 TLSv1.1 协议,请在 config.yaml 的配置项 apisix.ssl.ssl_ciphers 增加 TLSv1.1 协议所支持的加密套件。** ## ssl_protocols 配置 ### 静态配置 静态配置中 config.yaml 的 ssl_protocols 参数会作用于 APISIX 全局,但是不能动态修改,仅当匹配的 SSL 资源未设置 `ssl_protocols`,静态配置才会生效。 ```yaml apisix: ssl: ssl_protocols: TLSv1.2 TLSv1.3 # default TLSv1.2 TLSv1.3 ``` ### 动态配置 使用 ssl 资源中 ssl_protocols 字段动态的为每一个 SNI 指定不同的 TLS 协议版本。 指定 test.com 域名使用 TLSv1.2 TLSv1.3 协议版本: ```bash { "cert": "$cert", "key": "$key", "snis": ["test.com"], "ssl_protocols": [ "TLSv1.2", "TLSv1.3" ] } ``` ### 注意事项 - 动态配置优先级比静态配置更高,当 ssl 资源配置项 ssl_protocols 不为空时 静态配置将会被覆盖。 - 静态配置作用于全局需要重启 apisix 才能生效。 - 动态配置可细粒度的控制每个 SNI 的 TLS 协议版本,并且能够动态修改,相比于静态配置更加灵活。 ## 使用示例 ### 如何指定 TLSv1.1 协议 存在一些老旧的客户端,仍然采用较低级别的 TLSv1.1 协议版本,而新的产品则使用较高安全级别的 TLS 协议版本。如果让新产品支持 TLSv1.1 可能会带来一些安全隐患。为了保证 API 的安全性,我们需要在协议版本之间进行灵活转换。 例如:test.com 是老旧客户端所使用的域名,需要将其配置为 TLSv1.1 而 test2.com 属于新产品,同时支持了 TLSv1.2,TLSv1.3 协议。 1. config.yaml 配置。 ```yaml apisix: ssl: ssl_protocols: TLSv1.3 # ssl_ciphers is for reference only ssl_ciphers: ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA ``` 2. 为 test.com 域名指定 TLSv1.1 协议版本。 :::note 您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量: ```bash admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g') ``` ::: ```bash curl http://127.0.0.1:9180/apisix/admin/ssls/1 \ -H "X-API-KEY: $admin_key" -X PUT -d ' { "cert" : "'"$(cat server.crt)"'", "key": "'"$(cat server.key)"'", "snis": ["test.com"], "ssl_protocols": [ "TLSv1.1" ] }' ``` 3. 为 test.com 创建 SSL 对象,未指定 TLS 协议版本,将默认使用静态配置。 ```bash curl http://127.0.0.1:9180/apisix/admin/ssls/1 \ -H "X-API-KEY: $admin_key" -X PUT -d ' { "cert" : "'"$(cat server2.crt)"'", "key": "'"$(cat server2.key)"'", "snis": ["test2.com"] }' ``` 4. 访问验证 使用 TLSv1.3 访问 test.com 失败: ```shell $ curl --tls-max 1.3 --tlsv1.3 https://test.com:9443 -v -k -I * Trying 127.0.0.1:9443... * Connected to test.com (127.0.0.1) port 9443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt * CApath: /etc/ssl/certs * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS alert, protocol version (582): * error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version * Closing connection 0 curl: (35) error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version ``` 使用 TLSv1.1 访问 test.com 成功: ```shell $ curl --tls-max 1.1 --tlsv1.1 https://test.com:9443 -v -k -I * Trying 127.0.0.1:9443... * Connected to test.com (127.0.0.1) port 9443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt * CApath: /etc/ssl/certs * TLSv1.1 (OUT), TLS handshake, Client hello (1): * TLSv1.1 (IN), TLS handshake, Server hello (2): * TLSv1.1 (IN), TLS handshake, Certificate (11): * TLSv1.1 (IN), TLS handshake, Server key exchange (12): * TLSv1.1 (IN), TLS handshake, Server finished (14): * TLSv1.1 (OUT), TLS handshake, Client key exchange (16): * TLSv1.1 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.1 (OUT), TLS handshake, Finished (20): * TLSv1.1 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.1 / ECDHE-RSA-AES256-SHA ``` 使用 TLSv1.3 访问 test2.com 成功: ```shell $ curl --tls-max 1.3 --tlsv1.3 https://test2.com:9443 -v -k -I * Trying 127.0.0.1:9443... * Connected to test2.com (127.0.0.1) port 9443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt * CApath: /etc/ssl/certs * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): * TLSv1.3 (IN), TLS handshake, Certificate (11): * TLSv1.3 (IN), TLS handshake, CERT verify (15): * TLSv1.3 (IN), TLS handshake, Finished (20): * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.3 (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 ``` 使用 TLSv1.1 访问 test2.com 失败: ```shell curl --tls-max 1.1 --tlsv1.1 https://test2.com:9443 -v -k -I * Trying 127.0.0.1:9443... * Connected to test2.com (127.0.0.1) port 9443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt * CApath: /etc/ssl/certs * TLSv1.1 (OUT), TLS handshake, Client hello (1): * TLSv1.1 (IN), TLS alert, protocol version (582): * error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version * Closing connection 0 curl: (35) error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version ``` ### 证书关联多个域名,但域名之间使用不同的 TLS 协议 有时候,我们可能会遇到这样一种情况,即一个证书关联了多个域名,但是它们需要使用不同的 TLS 协议来保证安全性。例如 test.com 域名需要使用 TlSv1.2 协议,而 test2.com 域名则需要使用 TLSv1.3 协议。在这种情况下,我们不能简单地为所有的域名创建一个 SSL 对象,而是需要为每个域名单独创建一个 SSL 对象,并指定相应的协议版本。这样,我们就可以根据不同的域名和协议版本来进行正确的 SSL 握手和加密通信。示例如下: 1. 使用证书为 test.com 创建 ssl 对象,并指定 TLSv1.2 协议。 ```bash curl http://127.0.0.1:9180/apisix/admin/ssls/1 \ -H "X-API-KEY: $admin_key" -X PUT -d ' { "cert" : "'"$(cat server.crt)"'", "key": "'"$(cat server.key)"'", "snis": ["test.com"], "ssl_protocols": [ "TLSv1.2" ] }' ``` 2. 使用与 test.com 同一证书,为 test2.com 创建 ssl 对象,并指定 TLSv1.3 协议。 ```bash curl http://127.0.0.1:9180/apisix/admin/ssls/2 \ -H "X-API-KEY: $admin_key" -X PUT -d ' { "cert" : "'"$(cat server.crt)"'", "key": "'"$(cat server.key)"'", "snis": ["test2.com"], "ssl_protocols": [ "TLSv1.3" ] }' ``` 3. 访问验证 使用 TLSv1.2 访问 test.com 成功: ```shell $ curl --tls-max 1.2 --tlsv1.2 https://test.com:9443 -v -k -I * Trying 127.0.0.1:9443... * Connected to test.com (127.0.0.1) port 9443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt * CApath: /etc/ssl/certs * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * TLSv1.2 (IN), TLS handshake, Finished (20): * SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256 * ALPN, server accepted to use h2 * Server certificate: * subject: C=AU; ST=Some-State; O=Internet Widgits Pty Ltd; CN=test.com * start date: Jul 20 15:50:08 2023 GMT * expire date: Jul 17 15:50:08 2033 GMT * issuer: C=AU; ST=Some-State; O=Internet Widgits Pty Ltd; CN=test.com * SSL certificate verify result: EE certificate key too weak (66), continuing anyway. * Using HTTP2, server supports multi-use * Connection state changed (HTTP/2 confirmed) * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 * Using Stream ID: 1 (easy handle 0x5608905ee2e0) > HEAD / HTTP/2 > Host: test.com:9443 > user-agent: curl/7.74.0 > accept: */* ``` 使用 TLSv1.3 协议访问 test.com 失败: ```shell $ curl --tls-max 1.3 --tlsv1.3 https://test.com:9443 -v -k -I * Trying 127.0.0.1:9443... * Connected to test.com (127.0.0.1) port 9443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt * CApath: /etc/ssl/certs * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS alert, protocol version (582): * error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version * Closing connection 0 curl: (35) error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version ``` 使用 TLSv1.3 协议访问 test2.com 成功: ```shell $ curl --tls-max 1.3 --tlsv1.3 https://test2.com:9443 -v -k -I * Trying 127.0.0.1:9443... * Connected to test2.com (127.0.0.1) port 9443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt * CApath: /etc/ssl/certs * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): * TLSv1.3 (IN), TLS handshake, Certificate (11): * TLSv1.3 (IN), TLS handshake, CERT verify (15): * TLSv1.3 (IN), TLS handshake, Finished (20): * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.3 (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 * ALPN, server accepted to use h2 * Server certificate: * subject: C=AU; ST=Some-State; O=Internet Widgits Pty Ltd; CN=test2.com * start date: Jul 20 16:05:47 2023 GMT * expire date: Jul 17 16:05:47 2033 GMT * issuer: C=AU; ST=Some-State; O=Internet Widgits Pty Ltd; CN=test2.com * SSL certificate verify result: EE certificate key too weak (66), continuing anyway. * Using HTTP2, server supports multi-use * Connection state changed (HTTP/2 confirmed) * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 * Using Stream ID: 1 (easy handle 0x55569cbe42e0) > HEAD / HTTP/2 > Host: test2.com:9443 > user-agent: curl/7.74.0 > accept: */* > * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): * old SSL session ID is stale, removing ``` 使用 TLSv1.2 协议访问 test2.com 失败: ```shell $ curl --tls-max 1.2 --tlsv1.2 https://test2.com:9443 -v -k -I * Trying 127.0.0.1:9443... * Connected to test2.com (127.0.0.1) port 9443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt * CApath: /etc/ssl/certs * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS alert, protocol version (582): * error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version * Closing connection 0 curl: (35) error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version ```