TLS PSK usage with ZabbixSender
KostyaEsmukov opened this issue · 5 comments
I've spent quite a lot of time trying to set up a TLS connection with PSK. I finally managed to do that, so I thought I'd share my solution in hope that it would save someone time.
The python ssl
package doesn't provide support for PSK, it supports just the certificates. But there's a nice little package which does provide support for TLS PSK: https://github.com/drbild/sslpsk
The tricks are:
sslpsk
expects that itswrap_socket
would be called aftersocket.connect(...)
, while thessl.wrap_socket
expects that it would be called beforesocket.connect(...)
.- Zabbix server seems to accept only a single TLS cipher, which the client might not announce (I guess because it is a weak one).
So here is a solution that works for me with Zabbix server 4.2:
import functools
import ssl
import sslpsk
from pyzabbix import ZabbixMetric, ZabbixSender
class PyZabbixPSKSocketWrapper:
"""Implements ssl.wrap_socket with PSK instead of certificates.
Proxies calls to a `socket` instance.
"""
def __init__(self, sock, *, identity, psk):
self.__sock = sock
self.__identity = identity
self.__psk = psk
def connect(self, *args, **kwargs):
# `sslpsk.wrap_socket` must be called *after* socket.connect,
# while the `ssl.wrap_socket` must be called *before* socket.connect.
self.__sock.connect(*args, **kwargs)
# `sslv3 alert bad record mac` exception means incorrect PSK
self.__sock = sslpsk.wrap_socket(
self.__sock,
# https://github.com/zabbix/zabbix/blob/f0a1ad397e5653238638cd1a65a25ff78c6809bb/src/libs/zbxcrypto/tls.c#L3231
ssl_version=ssl.PROTOCOL_TLSv1_2,
# https://github.com/zabbix/zabbix/blob/f0a1ad397e5653238638cd1a65a25ff78c6809bb/src/libs/zbxcrypto/tls.c#L3179
ciphers="PSK-AES128-CBC-SHA",
psk=(self.__psk, self.__identity),
)
def __getattr__(self, name):
return getattr(self.__sock, name)
sender = ZabbixSender(
zabbix_server="my.zabbix.host",
socket_wrapper=functools.partial(
PyZabbixPSKSocketWrapper,
identity="PSK myidentity", # your PSK identity
psk=bytes.fromhex(
"0cd204cf169ade0bbdcd13c95594eadd008eed1b4411856b6e16e10ee6b69458" # your PSK
),
),
)
It would be nice if ZabbixSender(use_config=True)
could automatically detect PSK settings from the config and use them, but I guess this solution might seem to be a bit hacky to be included to the package. Especially given that the sslpsk
package on pypi does not provide manylinux/macos wheels and needs openssl headers and gcc to be present on the system to be installed.
I would be glad to know if there's a cleaner way to achieve the TLS PSK support with this package.
I have tested this on my landscape and it works perfectly.
Works perfectly on Zabbix 5, thanks for sharing.
Hello.
I guess this problem isn't fixed yet. Zabbix Agent 2 is working fine but I get these messages in proxy log.
218746:20210902:103052.576 connection of type "unencrypted" is not allowed for host "piapc"
218744:20210902:103053.697 connection of type "unencrypted" is not allowed for host "piapc"
218737:20210902:103054.811 connection of type "unencrypted" is not allowed for host "piapc"
@mcdir does your branch have these fixes applied?
Thanks in advance.
Thank you @KostyaEsmukov for providing this!
I hit a bug in the sslpsk lib.
AttributeError: '_ssl._SSLSocket' object has no attribute '_sslobj'
I could solve it by applying this patch manually to the file sslpsk.py
See also this thread.
After this it's working fine!!