加密和安全

加密

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 组件中使用 GnuTLSOpenSSL 1.1.0(或更新版本)库。GnuTLSOpenSSL 1.1.0 库支持带有完美前向保密的 PSK 密码套件。 较旧版本的 OpenSSL 库(1.0.1、1.0.2c)也支持 PSK,但可用的 PSK 密码套件不提供完美前向保密。

连接加密管理

Zabbix 中的连接可以使用:

用于指定 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
none\_none.png 未加密 未加密 加密、基于证书和基于 PSK 的加密
cert\_cert.png 加密,基于证书 加密,基于证书 未加密和基于 PSK 的加密
psk\_psk.png 加密,基于 PSK 加密,基于 PSK 未加密和基于证书的加密
psk\_none\_psk.png 加密,基于 PSK 未加密和基于 PSK 的加密 基于证书的加密
cert\_all.png 加密,基于证书 未加密、PSK 或基于证书的加密 -

连接默认不加密。必须分别为每个主机和 proxy 单独配置加密。

zabbix_get 和 zabbix_sender 的加密使用

请参阅 zabbix_getzabbix_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_getzabbix_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.confzabbix_proxy.confzabbix_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_getzabbix_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"