Skip to content

Commit ceb29cb

Browse files
committed
fixed TLS-PSK example code issue zabbix#7 by using built-in SSL features for Python 3.13+
1 parent 8d57619 commit ceb29cb

File tree

8 files changed

+430
-5
lines changed

8 files changed

+430
-5
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Copyright (C) 2001-2023 Zabbix SIA
2+
#
3+
# Zabbix SIA licenses this file to you under the MIT License.
4+
# See the LICENSE file in the project root for more information.
5+
6+
import ssl
7+
import asyncio
8+
from zabbix_utils import AsyncGetter
9+
10+
# !!! IMPORTANT
11+
# The code example below is supported only from Python version 3.13 onwards.
12+
13+
# Pre-Shared Key (PSK) and PSK Identity
14+
PSK_KEY = bytes.fromhex('608b0a0049d41fdb35a824ef0a227f24e5099c60aa935e803370a961c937d6f7')
15+
PSK_IDENTITY = b'PSKID'
16+
17+
# Zabbix agent parameters
18+
ZABBIX_AGENT = "127.0.0.1"
19+
ZABBIX_PORT = 10050
20+
21+
22+
# Create and configure an SSL context for secure communication with the Zabbix server.
23+
def custom_context(*args, **kwargs) -> ssl.SSLContext:
24+
# Create an SSL context for TLS client
25+
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
26+
27+
# Disable hostname verification
28+
context.check_hostname = False
29+
30+
# Set the verification mode to require a valid certificate
31+
context.verify_mode = ssl.CERT_NONE
32+
33+
# Set the maximum allowed version of the TLS protocol to TLS 1.2
34+
context.maximum_version = ssl.TLSVersion.TLSv1_2
35+
36+
# Set the ciphers to use for the connection
37+
context.set_ciphers('PSK')
38+
39+
# Set up the callback function to provide the PSK and identity when requested
40+
context.set_psk_client_callback(lambda hint: (PSK_IDENTITY, PSK_KEY))
41+
42+
# Return the customized SSL context
43+
return context
44+
45+
46+
async def main():
47+
"""
48+
The main function to perform asynchronous tasks.
49+
"""
50+
51+
# Create a AsyncGetter instance with a custom SSL context
52+
agent = AsyncGetter(
53+
host=ZABBIX_AGENT,
54+
port=ZABBIX_PORT,
55+
ssl_context=custom_context
56+
)
57+
58+
# Send a Zabbix agent query for system information (e.g., uname)
59+
resp = await agent.get('system.uname')
60+
61+
# Check if there was an error in the response
62+
if resp.error:
63+
# Print the error message
64+
print("An error occurred while trying to get the value:", resp.error)
65+
else:
66+
# Print the value obtained for the specified item key item
67+
print("Received value:", resp.value)
68+
69+
70+
# Run the main coroutine
71+
asyncio.run(main())

examples/get/synchronous/psk_wrapper.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,21 @@
66
import ssl
77
from zabbix_utils import Getter
88

9+
# !!! IMPORTANT
10+
# The following code example is supposed to be used with Python up to the 3.12 version.
11+
# Starting with Python 3.13, TLS-PSK is supported by the built-in ssl module.
12+
913
# Try importing sslpsk3, fall back to sslpsk2 if not available
1014
try:
1115
import sslpsk3 as sslpsk
1216
except ImportError:
1317
# Import sslpsk2 if sslpsk3 is not available
1418
import sslpsk2 as sslpsk
1519

20+
# Zabbix agent parameters
21+
ZABBIX_AGENT = "127.0.0.1"
22+
ZABBIX_PORT = 10050
23+
1624

1725
# PSK wrapper function for SSL connection
1826
def psk_wrapper(sock):
@@ -29,10 +37,6 @@ def psk_wrapper(sock):
2937
)
3038

3139

32-
# Zabbix agent parameters
33-
ZABBIX_AGENT = "127.0.0.1"
34-
ZABBIX_PORT = 10050
35-
3640
# Create a Getter instance with PSK support
3741
agent = Getter(
3842
host=ZABBIX_AGENT,
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Copyright (C) 2001-2023 Zabbix SIA
2+
#
3+
# Zabbix SIA licenses this file to you under the MIT License.
4+
# See the LICENSE file in the project root for more information.
5+
6+
import ssl
7+
from zabbix_utils import Getter
8+
9+
# !!! IMPORTANT
10+
# The code example below is supported only from Python version 3.13 onwards.
11+
12+
# Zabbix agent parameters
13+
ZABBIX_AGENT = "127.0.0.1"
14+
ZABBIX_PORT = 10050
15+
16+
17+
# PSK wrapper function for SSL connection
18+
def psk_wrapper(sock):
19+
# Pre-Shared Key (PSK) and PSK Identity
20+
psk = bytes.fromhex('608b0a0049d41fdb35a824ef0a227f24e5099c60aa935e803370a961c937d6f7')
21+
psk_identity = b'PSKID'
22+
23+
# Create an SSL context for TLS client
24+
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
25+
26+
# Disable hostname verification
27+
context.check_hostname = False
28+
29+
# Set the verification mode to require a valid certificate
30+
context.verify_mode = ssl.CERT_NONE
31+
32+
# Set the maximum allowed version of the TLS protocol to TLS 1.2
33+
context.maximum_version = ssl.TLSVersion.TLSv1_2
34+
35+
# Set the ciphers to use for the connection
36+
context.set_ciphers('PSK')
37+
38+
# Set up the callback function to provide the PSK and identity when requested
39+
context.set_psk_client_callback(lambda hint: (psk_identity, psk))
40+
41+
# Wrap the socket to establish an SSL connection with PSK
42+
return context.wrap_socket(sock)
43+
44+
45+
# Create a Getter instance with PSK support
46+
agent = Getter(
47+
host=ZABBIX_AGENT,
48+
port=ZABBIX_PORT,
49+
socket_wrapper=psk_wrapper
50+
)
51+
52+
# Send a Zabbix agent query for system information (e.g., uname)
53+
resp = agent.get('system.uname')
54+
55+
# Check if there was an error in the response
56+
if resp.error:
57+
# Print the error message
58+
print("An error occurred while trying to get the value:", resp.error)
59+
else:
60+
# Print the value obtained for the specified item key item
61+
print("Received value:", resp.value)
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Copyright (C) 2001-2023 Zabbix SIA
2+
#
3+
# Zabbix SIA licenses this file to you under the MIT License.
4+
# See the LICENSE file in the project root for more information.
5+
6+
import ssl
7+
import asyncio
8+
from zabbix_utils import AsyncSender
9+
10+
# !!! IMPORTANT
11+
# The code example below is supported only from Python version 3.13 onwards.
12+
13+
# Zabbix server details
14+
ZABBIX_SERVER = "zabbix-server.example.com"
15+
ZABBIX_PORT = 10051
16+
17+
# Pre-Shared Key (PSK) and PSK Identity
18+
PSK_KEY = bytes.fromhex('608b0a0049d41fdb35a824ef0a227f24e5099c60aa935e803370a961c937d6f7')
19+
PSK_IDENTITY = b'PSKID'
20+
21+
22+
# Create and configure an SSL context for secure communication with the Zabbix server.
23+
def custom_context(*args, **kwargs) -> ssl.SSLContext:
24+
# Create an SSL context for TLS client
25+
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
26+
27+
# Disable hostname verification
28+
context.check_hostname = False
29+
30+
# Set the verification mode to require a valid certificate
31+
context.verify_mode = ssl.CERT_NONE
32+
33+
# Set the maximum allowed version of the TLS protocol to TLS 1.2
34+
context.maximum_version = ssl.TLSVersion.TLSv1_2
35+
36+
# Set the ciphers to use for the connection
37+
context.set_ciphers('PSK')
38+
39+
# Set up the callback function to provide the PSK and identity when requested
40+
context.set_psk_client_callback(lambda hint: (PSK_IDENTITY, PSK_KEY))
41+
42+
# Return the customized SSL context
43+
return context
44+
45+
46+
async def main():
47+
"""
48+
The main function to perform asynchronous tasks.
49+
"""
50+
51+
# Create an instance of AsyncSender with a custom SSL context
52+
sender = AsyncSender(
53+
server=ZABBIX_SERVER,
54+
port=ZABBIX_PORT,
55+
ssl_context=custom_context
56+
)
57+
58+
# Send a value to a Zabbix server/proxy with specified parameters
59+
# Parameters: (host, key, value, clock, ns)
60+
response = await sender.send_value('host', 'item.key', 'value', 1695713666, 30)
61+
62+
# Check if the value sending was successful
63+
if response.failed == 0:
64+
# Print a success message along with the response time
65+
print(f"Value sent successfully in {response.time}")
66+
else:
67+
# Print a failure message
68+
print("Failed to send value")
69+
70+
# Run the main coroutine
71+
asyncio.run(main())
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Copyright (C) 2001-2023 Zabbix SIA
2+
#
3+
# Zabbix SIA licenses this file to you under the MIT License.
4+
# See the LICENSE file in the project root for more information.
5+
6+
import ssl
7+
import asyncio
8+
from zabbix_utils import AsyncSender
9+
10+
# !!! IMPORTANT
11+
# The code example below is supported only from Python version 3.13 onwards.
12+
13+
# Zabbix server details
14+
ZABBIX_SERVER = "zabbix-server.example.com"
15+
ZABBIX_PORT = 10051
16+
17+
18+
# Create and configure an SSL context for secure communication with the Zabbix server.
19+
def custom_context(config) -> ssl.SSLContext:
20+
psk = None
21+
22+
# Try to get PSK key and identity
23+
psk_identity = config.get('tlspskidentity').encode('utf-8')
24+
psk_file = config.get('tlspskfile')
25+
26+
# Read PSK from file if specified
27+
if psk_file:
28+
with open(psk_file, encoding='utf-8') as f:
29+
psk = bytes.fromhex(f.read())
30+
31+
# Create an SSL context for TLS client
32+
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
33+
34+
# Disable hostname verification
35+
context.check_hostname = False
36+
37+
# Set the verification mode to require a valid certificate
38+
context.verify_mode = ssl.CERT_NONE
39+
40+
# Set the maximum allowed version of the TLS protocol to TLS 1.2
41+
context.maximum_version = ssl.TLSVersion.TLSv1_2
42+
43+
# Set the ciphers to use for the connection
44+
context.set_ciphers('PSK')
45+
46+
# Set up the callback function to provide the PSK and identity when requested
47+
context.set_psk_client_callback(lambda hint: (psk_identity, psk))
48+
49+
# Return the customized SSL context
50+
return context
51+
52+
53+
async def main():
54+
"""
55+
The main function to perform asynchronous tasks.
56+
"""
57+
58+
# Create an instance of AsyncSender with a custom SSL context
59+
sender = AsyncSender(
60+
server=ZABBIX_SERVER,
61+
port=ZABBIX_PORT,
62+
use_config=True,
63+
ssl_context=custom_context
64+
)
65+
66+
# Send a value to a Zabbix server/proxy with specified parameters
67+
# Parameters: (host, key, value, clock, ns)
68+
response = await sender.send_value('host', 'item.key', 'value', 1695713666, 30)
69+
70+
# Check if the value sending was successful
71+
if response.failed == 0:
72+
# Print a success message along with the response time
73+
print(f"Value sent successfully in {response.time}")
74+
else:
75+
# Print a failure message
76+
print("Failed to send value")
77+
78+
# Run the main coroutine
79+
asyncio.run(main())

examples/sender/synchronous/psk_wrapper.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
import ssl
77
from zabbix_utils import Sender
88

9+
# !!! IMPORTANT
10+
# The following code example is supposed to be used with Python up to the 3.12 version.
11+
# Starting with Python 3.13, TLS-PSK is supported by the built-in ssl module.
12+
913
# Try importing sslpsk3, fall back to sslpsk2 if not available
1014
try:
1115
import sslpsk3 as sslpsk
@@ -15,7 +19,7 @@
1519

1620

1721
# PSK wrapper function for SSL connection
18-
def psk_wrapper(sock, tls):
22+
def psk_wrapper(sock, *args, **kwargs):
1923
# Pre-Shared Key (PSK) and PSK Identity
2024
psk = bytes.fromhex('608b0a0049d41fdb35a824ef0a227f24e5099c60aa935e803370a961c937d6f7')
2125
psk_identity = b'PSKID'

0 commit comments

Comments
 (0)