加密和安全
加密
Zabbix 支持 Zabbix 组件之间使用传输层安全(TLS)协议 v.1.2 和 1.3(取决于加密库)进行加密通信。支持基于证书和基于预共享密钥的加密。
可为以下连接配置加密:
- Zabbix 服务器、Zabbix proxy、Zabbix agent、Zabbix web service、zabbix_sender 和 zabbix_get 工具之间
- 到 Zabbix 数据库 来自 Zabbix 前端和 服务器/proxy
- Zabbix 前端和 Zabbix 服务器之间
加密是可选的,并且可针对各个组件单独配置:
- 某些 proxy 和 agent 可以配置为与服务器使用基于证书的加密,而其他 proxy 和 agent 可以使用基于预共享密钥的加密,还有一些则继续使用未加密通信(与之前相同)。
- 服务器(proxy)可以针对不同主机使用不同的加密配置。
Zabbix 守护进程程序对加密和未加密的入站连接使用同一个监听端口。启用加密不需要在防火墙上开放新的端口。
限制
- 私钥以明文形式存储在 Zabbix 组件在启动期间可读取的文件中。
- 预共享密钥在 Zabbix 前端中输入,并以明文形式存储在 Zabbix 数据库中。
- 内置加密不会保护运行 Zabbix 前端的 web 服务器与用户 web 浏览器之间的通信。
- 目前,每个加密连接都会通过完整的 TLS 握手建立,不支持会话缓存和票据。
- 启用加密会增加监控项检查和动作所需的时间,具体取决于网络延迟:
- 例如,如果数据包延迟为 100ms,那么打开 TCP 连接并发送未加密请求大约需要 200ms。使用加密时,建立 TLS 连接大约会额外增加 1000 ms。
- 可能需要增加超时时间,否则某些在 agent 上运行远程脚本的监控项和动作在未加密连接下可以正常工作,但在加密连接下会因超时而失败。
- 网络发现 不支持加密。网络发现执行的 Zabbix agent 检查将不会加密;如果 Zabbix agent 配置为拒绝未加密连接,这类检查将不会成功。
编译支持加密的 Zabbix
为了支持加密,Zabbix 必须使用以下受支持的加密库之一进行编译和链接:
- GnuTLS - 从 3.1.18 版本开始
- OpenSSL - 1.0.1、1.0.2、1.1.0、1.1.1、3.0.x - 3.5.x 版本
- LibreSSL - 已在 2.7.4、2.8.2 版本上测试:
- 不支持 LibreSSL 2.6.x
- LibreSSL 作为与 OpenSSL 兼容的替代品受到支持;
不会使用新的
tls_*()、LibreSSL 特有的 API 函数。 使用 LibreSSL 编译的 Zabbix 组件将无法使用 PSK,只能使用证书。
您可以参考这些最佳实践,了解有关为 Zabbix 前端配置 SSL 的更多信息。
通过在 "configure" 脚本中指定相应的选项来选择库:
--with-gnutls[=DIR]--with-openssl[=DIR](也用于 LibreSSL)
例如,要使用 OpenSSL 为服务器和 agent 配置源代码,可以使用如下命令:
./configure --enable-server --enable-agent --with-mysql --enable-ipv6 --with-net-snmp --with-libcurl --with-libxml2 --with-openssl
不同的 Zabbix 组件可以使用不同的加密库进行编译(例如,服务器使用 OpenSSL,agent 使用 GnuTLS)。
如果您计划使用预共享密钥(PSK), 建议在使用 PSK 的 Zabbix 组件中使用 GnuTLS 或 OpenSSL 1.1.0(或更新版本)库。GnuTLS 和 OpenSSL 1.1.0 库支持带有完美前向保密的 PSK 密码套件。 较旧版本的 OpenSSL 库(1.0.1、1.0.2c)也支持 PSK,但可用的 PSK 密码套件不提供完美前向保密。
连接加密管理
Zabbix 中的连接可以使用:
- 不加密(默认)
- 基于 RSA 证书的加密
- 基于 PSK 的加密
用于指定 Zabbix 组件之间加密方式的两个重要参数是:
- TLSConnect - 指定出站连接使用哪种加密方式(未加密、PSK 或证书)
- TLSAccept - 指定允许哪些类型的入站连接(未加密、PSK 或证书)。可以指定一个或多个值。
TLSConnect 用于 Zabbix proxy(主动模式下,仅指定到服务器的连接)和 Zabbix agent(用于主动检查)的配置文件中。在 Zabbix 前端中,TLSConnect 的对应项是 数据采集 > 主机 > <some host> > 加密 选项卡中的 来自主机的连接 字段,以及 管理 > proxy > <some proxy> > 加密 选项卡中的 来自 proxy 的连接 字段。如果配置的连接加密类型失败,不会尝试其他加密类型。
TLSAccept 用于 Zabbix proxy(被动模式下,仅指定来自服务器的连接)和 Zabbix agent(用于被动检查)的配置文件中。在 Zabbix 前端中,TLSAccept 的对应项是 数据采集 > 主机 > <some host> > 加密 选项卡中的 来自主机的连接 字段,以及 管理 > proxy > <some proxy> > 加密 选项卡中的 来自 proxy 的连接 字段。
通常,您只会为入站连接配置一种加密类型。但您可能希望切换加密类型,例如从未加密切换到基于证书的加密,同时尽量减少停机时间并保留回滚可能性。要实现这一点:
- 在 agent 配置文件中设置
TLSAccept=unencrypted,cert,然后重启 Zabbix agent - 使用证书通过 zabbix_get 测试与 agent 的连接。如果可用,则可以在 Zabbix 前端中重新配置该 agent 的加密方式:进入 数据采集 > 主机 > <some host> > 加密 选项卡,将 来自主机的连接 设置为 "Certificate"。
- 当服务器配置缓存更新后(如果该主机由 proxy 监控,则 proxy 配置也会更新),到该 agent 的连接将被加密
- 如果一切按预期工作,您可以在 agent 配置文件中设置
TLSAccept=cert,然后重启 Zabbix agent。此时 agent 将只接受基于证书的加密连接。未加密和基于 PSK 的连接将被拒绝。
在服务器和 proxy 上,工作方式也类似。如果在 Zabbix 前端的主机配置中将 来自主机的连接 设置为 "Certificate",那么只有基于证书加密的连接才会被来自 agent(主动检查)和 zabbix_sender(trapper 监控项)的连接所接受。
大多数情况下,您会将入站和出站连接配置为使用相同的加密类型,或者完全不使用加密。但从技术上讲,也可以进行非对称配置,例如入站连接使用基于证书的加密,而出站连接使用基于 PSK 的加密。
每个主机的加密配置都会显示在 Zabbix 前端的 数据采集 > 主机 中的 agent 加密 列中。例如:
| Example | Connections to host | Allowed connections from host | Rejected connections from host |
|---|---|---|---|
![]() |
未加密 | 未加密 | 加密、基于证书和基于 PSK 的加密 |
![]() |
加密,基于证书 | 加密,基于证书 | 未加密和基于 PSK 的加密 |
![]() |
加密,基于 PSK | 加密,基于 PSK | 未加密和基于证书的加密 |
![]() |
加密,基于 PSK | 未加密和基于 PSK 的加密 | 基于证书的加密 |
![]() |
加密,基于证书 | 未加密、PSK 或基于证书的加密 | - |
连接默认不加密。必须分别为每个主机和 proxy 单独配置加密。
zabbix_get 和 zabbix_sender 的加密使用
请参阅 zabbix_get 和 zabbix_sender 的手册页,了解如何在 加密环境中使用它们。
密码套件
默认情况下,密码套件在 Zabbix 启动期间在内部进行配置。
GnuTLS 和 OpenSSL 也支持用户配置的密码套件。用户可以根据自己的安全策略配置密码套件。使用此功能是可选的(内置默认密码套件仍然可用)。
对于使用默认设置编译的加密库,Zabbix 内置规则通常会生成以下密码套件(按优先级从高到低排序):
| Library | Certificate ciphersuites | PSK ciphersuites |
|---|---|---|
| GnuTLS 3.1.18 | TLS_ECDHE_RSA_AES_128_GCM_SHA256 TLS_ECDHE_RSA_AES_128_CBC_SHA256 TLS_ECDHE_RSA_AES_128_CBC_SHA1 TLS_RSA_AES_128_GCM_SHA256 TLS_RSA_AES_128_CBC_SHA256 TLS_RSA_AES_128_CBC_SHA1 |
TLS_ECDHE_PSK_AES_128_CBC_SHA256 TLS_ECDHE_PSK_AES_128_CBC_SHA1 TLS_PSK_AES_128_GCM_SHA256 TLS_PSK_AES_128_CBC_SHA256 TLS_PSK_AES_128_CBC_SHA1 |
| OpenSSL 1.0.2c | ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES128-SHA AES128-GCM-SHA256 AES128-SHA256 AES128-SHA |
PSK-AES128-CBC-SHA |
| OpenSSL 1.1.0 | ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES128-SHA AES128-GCM-SHA256 AES128-CCM8 AES128-CCM AES128-SHA256 AES128-SHA |
ECDHE-PSK-AES128-CBC-SHA256 ECDHE-PSK-AES128-CBC-SHA PSK-AES128-GCM-SHA256 PSK-AES128-CCM8 PSK-AES128-CCM PSK-AES128-CBC-SHA256 PSK-AES128-CBC-SHA |
| OpenSSL 1.1.1d | TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES128-SHA AES128-GCM-SHA256 AES128-CCM8 AES128-CCM AES128-SHA256 AES128-SHA |
TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256 ECDHE-PSK-AES128-CBC-SHA256 ECDHE-PSK-AES128-CBC-SHA PSK-AES128-GCM-SHA256 PSK-AES128-CCM8 PSK-AES128-CCM PSK-AES128-CBC-SHA256 PSK-AES128-CBC-SHA |
用户配置的 ciphersuite
内置的 ciphersuite 选择条件可以通过用户配置的 ciphersuite 覆盖。
用户配置的 ciphersuite 是一项面向高级用户的功能,这些用户了解 TLS ciphersuite、其安全性以及错误可能带来的后果,并且熟悉 TLS 故障排查。
可以使用以下参数覆盖内置的 ciphersuite 选择条件:
| 覆盖范围 | 参数 | 值 | 说明 |
|---|---|---|---|
| 证书的 ciphersuite 选择 | TLSCipherCert13 | 适用于 TLS 1.3 协议的有效 OpenSSL 1.1.1 cipher strings(其值会传递给 OpenSSL 函数 SSL_CTX_set_ciphersuites())。 |
基于证书的 TLS 1.3 ciphersuite 选择条件 仅适用于 OpenSSL 1.1.1 或更新版本。 |
| TLSCipherCert | 适用于 TLS 1.2 的有效 OpenSSL cipher strings 或有效的 GnuTLS priority strings。其值分别会传递给 SSL_CTX_set_cipher_list() 或 gnutls_priority_init() 函数。 |
基于证书的 TLS 1.2/1.3(GnuTLS)、TLS 1.2(OpenSSL)ciphersuite 选择条件 | |
| PSK 的 ciphersuite 选择 | TLSCipherPSK13 | 适用于 TLS 1.3 协议的有效 OpenSSL 1.1.1 cipher strings(其值会传递给 OpenSSL 函数 SSL_CTX_set_ciphersuites())。 |
基于 PSK 的 TLS 1.3 ciphersuite 选择条件 仅适用于 OpenSSL 1.1.1 或更新版本。 |
| TLSCipherPSK | 适用于 TLS 1.2 的有效 OpenSSL cipher strings 或有效的 GnuTLS priority strings。其值分别会传递给 SSL_CTX_set_cipher_list() 或 gnutls_priority_init() 函数。 |
基于 PSK 的 TLS 1.2/1.3(GnuTLS)、TLS 1.2(OpenSSL)ciphersuite 选择条件 | |
| 证书和 PSK 的组合 ciphersuite 列表 | TLSCipherAll13 | 适用于 TLS 1.3 协议的有效 OpenSSL 1.1.1 cipher strings(其值会传递给 OpenSSL 函数 SSL_CTX_set_ciphersuites())。 |
TLS 1.3 的 ciphersuite 选择条件 仅适用于 OpenSSL 1.1.1 或更新版本。 |
| TLSCipherAll | 适用于 TLS 1.2 的有效 OpenSSL cipher strings 或有效的 GnuTLS priority strings。其值分别会传递给 SSL_CTX_set_cipher_list() 或 gnutls_priority_init() 函数。 |
TLS 1.2/1.3(GnuTLS)、TLS 1.2(OpenSSL)的 ciphersuite 选择条件 |
要在 zabbix_get 和 zabbix_sender 工具中覆盖 ciphersuite 选择,请使用以下命令行参数:
--tls-cipher13--tls-cipher
这些新参数是可选的。如果未指定某个参数,则使用内部默认值。如果定义了某个参数,则不能为空。
如果在加密库中设置某个 TLSCipher* 值失败,则服务器、proxy 或 agent 将不会启动,并且会记录错误。
重要的是要理解每个参数适用的场景。
出站连接
最简单的情况是出站连接:
- 对于使用证书的出站连接 - 使用 TLSCipherCert13 或 TLSCipherCert
- 对于使用 PSK 的出站连接 - 使用 TLSCipherPSK13 或 TLSCipherPSK
- 对于 zabbix_get 和 zabbix_sender 工具,可以使用命令行
参数
--tls-cipher13或--tls-cipher(加密方式通过--tls-connect参数明确指定)
入站连接
对于入站连接,情况会稍微复杂一些,因为规则会因组件和配置而异。
对于 Zabbix agent:
| Agent connection setup | Cipher configuration |
|---|---|
| TLSConnect=cert | TLSCipherCert, TLSCipherCert13 |
| TLSConnect=psk | TLSCipherPSK, TLSCipherPSK13 |
| TLSAccept=cert | TLSCipherCert, TLSCipherCert13 |
| TLSAccept=psk | TLSCipherPSK, TLSCipherPSK13 |
| TLSAccept=cert,psk | TLSCipherAll, TLSCipherAll13 |
对于 Zabbix 服务器 和 proxy:
| Connection setup | Cipher configuration |
|---|---|
| Outgoing connections using PSK | TLSCipherPSK, TLSCipherPSK13 |
| Incoming connections using certificates | TLSCipherAll, TLSCipherAll13 |
| Incoming connections using PSK if server has no certificate | TLSCipherPSK, TLSCipherPSK13 |
| Incoming connections using PSK if server has certificate | TLSCipherAll, TLSCipherAll13 |
从上面的两个表中可以看出一些规律:
- 只有在使用证书和 PSK 基于的密码套件组合列表时,才可以指定 TLSCipherAll 和 TLSCipherAll13。出现这种情况有两种:服务器(proxy)已配置证书(如果加密库支持 PSK,则服务器和 proxy 始终会配置 PSK 密码套件;proxy 仅在加密库支持 PSK 时才会配置),agent 配置为同时接受基于证书和基于 PSK 的入站连接
- 在其他情况下,TLSCipherCert* 和/或 TLSCipherPSK* 就足够了
下表显示了 TLSCipher* 内置默认值。它们可以作为你自定义值的良好起点。
| Parameter | GnuTLS 3.6.12 |
|---|---|
| TLSCipherCert | NONE:+VERS-TLS1.2:+ECDHE-RSA:+RSA:+AES-128-GCM:+AES-128-CBC:+AEAD:+SHA256:+SHA1:+CURVE-ALL:+COMP-NULL:+SIGN-ALL:+CTYPE-X.509 |
| TLSCipherPSK | NONE:+VERS-TLS1.2:+ECDHE-PSK:+PSK:+AES-128-GCM:+AES-128-CBC:+AEAD:+SHA256:+SHA1:+CURVE-ALL:+COMP-NULL:+SIGN-ALL |
| TLSCipherAll | NONE:+VERS-TLS1.2:+ECDHE-RSA:+RSA:+ECDHE-PSK:+PSK:+AES-128-GCM:+AES-128-CBC:+AEAD:+SHA256:+SHA1:+CURVE-ALL:+COMP-NULL:+SIGN-ALL:+CTYPE-X.509 |
| Parameter | OpenSSL 1.1.1d 1 |
|---|---|
| TLSCipherCert13 | |
| TLSCipherCert | EECDH+aRSA+AES128:RSA+aRSA+AES128 |
| TLSCipherPSK13 | TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256 |
| TLSCipherPSK | kECDHEPSK+AES128:kPSK+AES128 |
| TLSCipherAll13 | |
| TLSCipherAll | EECDH+aRSA+AES128:RSA+aRSA+AES128:kECDHEPSK+AES128:kPSK+AES128 |
1 默认值在较旧的 OpenSSL 版本(1.0.1、1.0.2、1.1.0)、LibreSSL,以及在编译 OpenSSL 时未启用 PSK 支持的情况下会有所不同。
用户配置的密码套件示例
请参见下面的用户配置密码套件示例:
测试 cipher 字符串并仅允许 PFS cipher suites
要查看已选择了哪些 cipher suites,需要在配置文件中设置
'DebugLevel=4',或者为 zabbix_sender 使用 -vv 选项。
在获得所需的 cipher suites 之前,可能需要对 TLSCipher* 参数进行一些尝试。
为了仅微调 TLSCipher* 参数而多次重启 Zabbix 服务器、proxy 或 agent 是很不方便的。
更方便的方式是使用 zabbix_sender 或 openssl 命令。下面两种方法都介绍一下。
1. 使用 zabbix_sender。
先创建一个测试配置文件,例如 /home/zabbix/test.conf,其语法与 zabbix_agentd.conf 文件相同:
Hostname=nonexisting
ServerActive=nonexisting
TLSConnect=cert
TLSCAFile=/home/zabbix/ca.crt
TLSCertFile=/home/zabbix/agent.crt
TLSKeyFile=/home/zabbix/agent.key
TLSPSKIdentity=nonexisting
TLSPSKFile=/home/zabbix/agent.psk
在此示例中,你需要有效的 CA 和 agent 证书以及 PSK。 请根据你的环境调整证书和 PSK 文件的路径与名称。
如果你不使用证书,而只使用 PSK,可以使用更简单的测试文件:
Hostname=nonexisting
ServerActive=nonexisting
TLSConnect=psk
TLSPSKIdentity=nonexisting
TLSPSKFile=/home/zabbix/agentd.psk
可以通过运行 zabbix_sender 查看所选的 cipher suites(示例使用 OpenSSL 1.1.d 编译):
$ zabbix_sender -vv -c /home/zabbix/test.conf -k nonexisting_item -o 1 2>&1 | grep ciphersuites
zabbix_sender [41271]: DEBUG: zbx_tls_init_child() certificate ciphersuites: TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES128-SHA AES128-GCM-SHA256 AES128-CCM8 AES128-CCM AES128-SHA256 AES128-SHA
zabbix_sender [41271]: DEBUG: zbx_tls_init_child() PSK ciphersuites: TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256 ECDHE-PSK-AES128-CBC-SHA256 ECDHE-PSK-AES128-CBC-SHA PSK-AES128-GCM-SHA256 PSK-AES128-CCM8 PSK-AES128-CCM PSK-AES128-CBC-SHA256 PSK-AES128-CBC-SHA
zabbix_sender [41271]: DEBUG: zbx_tls_init_child() certificate and PSK ciphersuites: TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES128-SHA AES128-GCM-SHA256 AES128-CCM8 AES128-CCM AES128-SHA256 AES128-SHA ECDHE-PSK-AES128-CBC-SHA256 ECDHE-PSK-AES128-CBC-SHA PSK-AES128-GCM-SHA256 PSK-AES128-CCM8 PSK-AES128-CCM PSK-AES128-CBC-SHA256 PSK-AES128-CBC-SHA
这里可以看到默认选择的 cipher suites。这些默认值是为了确保与运行在较旧 OpenSSL 版本(1.0.1)的 Zabbix agent 兼容而选定的。
在较新的系统上,你可以通过只允许少数 cipher suites 来加强安全性,例如只允许带有 PFS(Perfect Forward Secrecy)的 cipher suites。下面尝试使用 TLSCipher* 参数仅允许带有 PFS 的 cipher suites。
如果使用 PSK,那么结果将无法与使用 OpenSSL 1.0.1 和 1.0.2 的系统互操作。 基于证书的加密应该可以正常工作。
向 test.conf 配置文件中添加两行:
TLSCipherCert=EECDH+aRSA+AES128
TLSCipherPSK=kECDHEPSK+AES128
然后再次测试:
$ zabbix_sender -vv -c /home/zabbix/test.conf -k nonexisting_item -o 1 2>&1 | grep ciphersuites
zabbix_sender [42892]: DEBUG: zbx_tls_init_child() certificate ciphersuites: TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES128-SHA
zabbix_sender [42892]: DEBUG: zbx_tls_init_child() PSK ciphersuites: TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256 ECDHE-PSK-AES128-CBC-SHA256 ECDHE-PSK-AES128-CBC-SHA
zabbix_sender [42892]: DEBUG: zbx_tls_init_child() certificate and PSK ciphersuites: TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES128-SHA AES128-GCM-SHA256 AES128-CCM8 AES128-CCM AES128-SHA256 AES128-SHA ECDHE-PSK-AES128-CBC-SHA256 ECDHE-PSK-AES128-CBC-SHA PSK-AES128-GCM-SHA256 PSK-AES128-CCM8 PSK-AES128-CCM PSK-AES128-CBC-SHA256 PSK-AES128-CBC-SHA
“certificate ciphersuites”和“PSK ciphersuites”列表已经发生变化——它们比之前更短,只包含 TLS 1.3 cipher suites 和符合预期的 TLS 1.2 ECDHE-* cipher suites。
2. 无法使用 zabbix_sender 测试 TLSCipherAll 和 TLSCipherAll13;它们不会影响上面示例中显示的“certificate and PSK ciphersuites”值。要调整 TLSCipherAll 和 TLSCipherAll13,需要在 agent、proxy 或服务器上进行尝试。
因此,如果只允许 PFS cipher suites,你可能需要添加最多三个参数:
TLSCipherCert=EECDH+aRSA+AES128
TLSCipherPSK=kECDHEPSK+AES128
TLSCipherAll=EECDH+aRSA+AES128:kECDHEPSK+AES128
到 zabbix_agentd.conf、zabbix_proxy.conf 和 zabbix_server.conf 中,如果它们都配置了证书,并且 agent 也使用了 PSK。
如果你的 Zabbix 环境只使用基于 PSK 的加密而不使用证书,那么只需要这一项:
TLSCipherPSK=kECDHEPSK+AES128
现在你已经了解其工作方式,还可以在 Zabbix 之外使用 openssl 命令测试 cipher suite 的选择。下面测试这三个 TLSCipher* 参数值:
$ openssl ciphers EECDH+aRSA+AES128 | sed 's/:/ /g'
TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES128-SHA
$ openssl ciphers kECDHEPSK+AES128 | sed 's/:/ /g'
TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256 ECDHE-PSK-AES128-CBC-SHA256 ECDHE-PSK-AES128-CBC-SHA
$ openssl ciphers EECDH+aRSA+AES128:kECDHEPSK+AES128 | sed 's/:/ /g'
TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256 TLS_AES_128_GCM_SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES128-SHA ECDHE-PSK-AES128-CBC-SHA256 ECDHE-PSK-AES128-CBC-SHA
你也可以使用带 -V 选项的 openssl ciphers,以获得更详细的输出:
$ openssl ciphers -V EECDH+aRSA+AES128:kECDHEPSK+AES128
0x13,0x02 - TLS_AES_256_GCM_SHA384 TLSv1.3 Kx=any Au=any Enc=AESGCM(256) Mac=AEAD
0x13,0x03 - TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any Au=any Enc=CHACHA20/POLY1305(256) Mac=AEAD
0x13,0x01 - TLS_AES_128_GCM_SHA256 TLSv1.3 Kx=any Au=any Enc=AESGCM(128) Mac=AEAD
0xC0,0x2F - ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD
0xC0,0x27 - ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256
0xC0,0x13 - ECDHE-RSA-AES128-SHA TLSv1 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA1
0xC0,0x37 - ECDHE-PSK-AES128-CBC-SHA256 TLSv1 Kx=ECDHEPSK Au=PSK Enc=AES(128) Mac=SHA256
0xC0,0x35 - ECDHE-PSK-AES128-CBC-SHA TLSv1 Kx=ECDHEPSK Au=PSK Enc=AES(128) Mac=SHA1
同样,你也可以测试 GnuTLS 的优先级字符串:
$ gnutls-cli -l --priority=NONE:+VERS-TLS1.2:+ECDHE-RSA:+AES-128-GCM:+AES-128-CBC:+AEAD:+SHA256:+CURVE-ALL:+COMP-NULL:+SIGN-ALL:+CTYPE-X.509
Cipher suites for NONE:+VERS-TLS1.2:+ECDHE-RSA:+AES-128-GCM:+AES-128-CBC:+AEAD:+SHA256:+CURVE-ALL:+COMP-NULL:+SIGN-ALL:+CTYPE-X.509
TLS_ECDHE_RSA_AES_128_GCM_SHA256 0xc0, 0x2f TLS1.2
TLS_ECDHE_RSA_AES_128_CBC_SHA256 0xc0, 0x27 TLS1.2
Protocols: VERS-TLS1.2
Ciphers: AES-128-GCM, AES-128-CBC
MACs: AEAD, SHA256
Key Exchange Algorithms: ECDHE-RSA
Groups: GROUP-SECP256R1, GROUP-SECP384R1, GROUP-SECP521R1, GROUP-X25519, GROUP-X448, GROUP-FFDHE2048, GROUP-FFDHE3072, GROUP-FFDHE4096, GROUP-FFDHE6144, GROUP-FFDHE8192
PK-signatures: SIGN-RSA-SHA256, SIGN-RSA-PSS-SHA256, SIGN-RSA-PSS-RSAE-SHA256, SIGN-ECDSA-SHA256, SIGN-ECDSA-SECP256R1-SHA256, SIGN-EdDSA-Ed25519, SIGN-RSA-SHA384, SIGN-RSA-PSS-SHA384, SIGN-RSA-PSS-RSAE-SHA384, SIGN-ECDSA-SHA384, SIGN-ECDSA-SECP384R1-SHA384, SIGN-EdDSA-Ed448, SIGN-RSA-SHA512, SIGN-RSA-PSS-SHA512, SIGN-RSA-PSS-RSAE-SHA512, SIGN-ECDSA-SHA512, SIGN-ECDSA-SECP521R1-SHA512, SIGN-RSA-SHA1, SIGN-ECDSA-SHA1
从 AES128 切换到 AES256
Zabbix 将 AES128 作为数据的内置默认值。假设您正在使用证书,并希望在 OpenSSL 1.1.1 上切换到 AES256。
这可以通过在 zabbix_server.conf 中添加相应参数来实现:
TLSCAFile=/home/zabbix/ca.crt
TLSCertFile=/home/zabbix/server.crt
TLSKeyFile=/home/zabbix/server.key
TLSCipherCert13=TLS_AES_256_GCM_SHA384
TLSCipherCert=EECDH+aRSA+AES256:-SHA1:-SHA384
TLSCipherPSK13=TLS_CHACHA20_POLY1305_SHA256
TLSCipherPSK=kECDHEPSK+AES256:-SHA1
TLSCipherAll13=TLS_AES_256_GCM_SHA384
TLSCipherAll=EECDH+aRSA+AES256:-SHA1:-SHA384
尽管实际只会使用与证书相关的密码套件,
但也定义了 TLSCipherPSK* 参数,以避免使用其默认值,因为默认值包含安全性较低的密码套件,以便实现更广泛的互操作性。PSK 密码套件无法在服务器/proxy 上完全禁用。
以及在 zabbix_agentd.conf 中:
TLSConnect=cert
TLSAccept=cert
TLSCAFile=/home/zabbix/ca.crt
TLSCertFile=/home/zabbix/agent.crt
TLSKeyFile=/home/zabbix/agent.key
TLSCipherCert13=TLS_AES_256_GCM_SHA384
TLSCipherCert=EECDH+aRSA+AES256:-SHA1:-SHA384
加密问题排查
一般建议:
- 首先要弄清在问题场景中,哪个组件充当 TLS 客户端,哪个组件充当 TLS 服务器。
Zabbix 服务器、proxy 和 agent 根据它们之间的交互方式,都可以充当 TLS 服务器和客户端。
例如,Zabbix 服务器连接 agent 进行被动检查时,充当 TLS 客户端。agent 则充当 TLS 服务器。
Zabbix agent 从 proxy 请求主动检查列表时,充当 TLS 客户端。proxy 则充当 TLS 服务器。
zabbix_get和zabbix_sender工具始终充当 TLS 客户端。 - Zabbix 使用双向认证。
双方都会验证对端,并且可能拒绝连接。
例如,Zabbix 服务器连接 agent 时,如果 agent 的证书无效,连接可能会立即关闭。反之亦然 -
Zabbix agent 接受来自服务器的连接时,如果服务器不被 agent 信任,也可能会关闭连接。 - 检查 TLS 客户端和 TLS 服务器两端的日志文件。
拒绝连接的一方通常会记录被拒绝的准确原因。另一方往往只会报告比较笼统的错误(例如,“Connection closed by peer”、“connection was non-properly terminated”)。 - 有时,配置错误的加密会导致令人困惑的错误消息,完全无法指向真正的原因。
在下面的小节中,我们尝试提供一份(远非穷尽的)消息及其可能原因的集合,以帮助排查问题。
请注意,不同的加密工具包(OpenSSL、GnuTLS)在相同问题场景下通常会产生不同的错误消息。
有时,错误消息甚至取决于双方所使用的加密工具包的具体组合。
连接类型或权限问题排查
服务器已配置为使用 PSK 连接到 agent,但 agent 仅接受未加密连接
在服务器或 proxy 日志中(使用 GnuTLS 3.3.16)
从 agent 获取值失败:zbx_tls_connect(): gnutls_handshake() 失败: \
-110 TLS 连接未正确终止。
在服务器或 proxy 日志中(使用 OpenSSL 1.0.2c)
从 agent 获取值失败:TCP 连接成功,无法在 [[127.0.0.1]:10050] 上建立 TLS: \
连接被对端关闭。请检查允许的连接类型和访问权限
一侧使用证书连接,但另一侧只接受 PSK,或反之
在任何日志中(使用 GnuTLS):
failed to accept an incoming connection: from 127.0.0.1: zbx_tls_accept(): gnutls_handshake() failed:\
-21 Could not negotiate a supported cipher suite.
在任何日志中(使用 OpenSSL 1.0.2c):
failed to accept an incoming connection: from 127.0.0.1: TLS handshake returned error code 1:\
file .\ssl\s3_srvr.c line 1411: error:1408A0C1:SSL routines:ssl3_get_client_hello:no shared cipher:\
TLS write fatal alert "handshake failure"
尝试使用启用了 TLS 支持编译的 Zabbix sender 向未启用 TLS 支持编译的 Zabbix 服务器/proxy 发送数据
在连接端日志中:
Linux:
...In zbx_tls_init_child()
...OpenSSL library (version OpenSSL 1.1.1 11 Sep 2018) initialized
...
...In zbx_tls_connect(): psk_identity:"PSK test sender"
...End of zbx_tls_connect():FAIL error:'connection closed by peer'
...send value error: TCP successful, cannot establish TLS to [[localhost]:10051]: connection closed by peer
Windows:
...OpenSSL library (version OpenSSL 1.1.1a 20 Nov 2018) initialized
...
...In zbx_tls_connect(): psk_identity:"PSK test sender"
...zbx_psk_client_cb() requested PSK identity "PSK test sender"
...End of zbx_tls_connect():FAIL error:'SSL_connect() I/O error: [0x00000000] The operation completed successfully.'
...send value error: TCP successful, cannot establish TLS to [[192.168.1.2]:10051]: SSL_connect() I/O error: [0x00000000] The operation completed successfully.
在接收端日志中:
...failed to accept an incoming connection: from 127.0.0.1: support for TLS was not compiled in
一侧使用 PSK 连接,但另一侧使用 LibreSSL 或在编译时未启用加密支持
LibreSSL 不支持 PSK。
在连接端日志中:
...TCP successful, cannot establish TLS to [[192.168.1.2]:10050]: SSL_connect() I/O error: [0] Success
在接受端日志中:
...failed to accept an incoming connection: from 192.168.1.2: support for PSK was not compiled in
在 Zabbix 前端中:
Get value from agent failed: TCP successful, cannot establish TLS to [[192.168.1.2]:10050]: SSL_connect() I/O error: [0] Success
一侧使用 PSK 连接,但另一侧使用已禁用 PSK 支持的 OpenSSL
在连接方日志中:
...TCP successful, cannot establish TLS to [[192.168.1.2]:10050]: SSL_connect() set result code to SSL_ERROR_SSL: file ../ssl/record/rec_layer_s3.c line 1536: error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure: SSL alert number 40: TLS read fatal alert "handshake failure"
在接受方日志中:
...failed to accept an incoming connection: from 192.168.1.2: TLS handshake set result code to 1: file ssl/statem/statem_srvr.c line 1422: error:1417A0C1:SSL routines:tls_post_process_client_hello:no shared cipher: TLS write fatal alert "handshake failure"




