Skip to content

TLS PSK usage with ZabbixSender #114

Open
@KostyaEsmukov

Description

@KostyaEsmukov

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 its wrap_socket would be called after socket.connect(...), while the ssl.wrap_socket expects that it would be called before socket.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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions