From 277754bf314d88239e18b93ab0c3e35b2809f1b2 Mon Sep 17 00:00:00 2001 From: Pascal Zimmermann Date: Wed, 5 Oct 2022 00:07:28 +0200 Subject: [PATCH 1/6] feat: Add first version of the MTLS feature --- CHANGELOG.md | 1 + README.rst | 6 +++++ influxdb_client/_async/rest.py | 22 +++++++++++-------- influxdb_client/_sync/rest.py | 6 +++++ influxdb_client/client/_base.py | 21 ++++++++++++++++++ influxdb_client/client/influxdb_client.py | 6 +++++ .../client/influxdb_client_async.py | 3 +++ influxdb_client/configuration.py | 5 +++++ 8 files changed, 61 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index afafbe49..45448b75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### Features 1. [#510](https://github.com/influxdata/influxdb-client-python/pull/510): Allow to use client's optional configs for initialization from file or environment properties +2. [#509](https://github.com/influxdata/influxdb-client-python/pull/509): MTLS support for the InfluxDB Python client ### Bug Fixes 1. [#512](https://github.com/influxdata/influxdb-client-python/pull/512): Exception propagation for asynchronous `QueryApi` [async/await] diff --git a/README.rst b/README.rst index 6d4358fb..66bc2186 100644 --- a/README.rst +++ b/README.rst @@ -197,6 +197,9 @@ The following options are supported: - ``timeout`` - socket timeout in ms (default value is 10000) - ``verify_ssl`` - set this to false to skip verifying SSL certificate when calling API from https server - ``ssl_ca_cert`` - set this to customize the certificate file to verify the peer +- ``cert_file`` - set this to customize the certificate client certificate file +- ``key_file`` - set this to customize the certificate client key file +- ``key_password`` - set this to customize the certificate client key file password - ``connection_pool_maxsize`` - set the number of connections to save that can be reused by urllib3 - ``auth_basic`` - enable http basic authentication when talking to a InfluxDB 1.8.x without authentication but is accessed via reverse proxy with basic authentication (defaults to false) - ``profilers`` - set the list of enabled `Flux profilers `_ @@ -226,6 +229,9 @@ Supported properties are: - ``INFLUXDB_V2_TIMEOUT`` - socket timeout in ms (default value is 10000) - ``INFLUXDB_V2_VERIFY_SSL`` - set this to false to skip verifying SSL certificate when calling API from https server - ``INFLUXDB_V2_SSL_CA_CERT`` - set this to customize the certificate file to verify the peer +- ``INFLUXDB_V2_CERT_FILE`` - set this to customize the certificate client certificate file +- ``INFLUXDB_V2_KEY_FILE`` - set this to customize the certificate client key file +- ``INFLUXDB_V2_KEY_PASSWORD`` - set this to customize the certificate client key file password - ``INFLUXDB_V2_CONNECTION_POOL_MAXSIZE`` - set the number of connections to save that can be reused by urllib3 - ``INFLUXDB_V2_AUTH_BASIC`` - enable http basic authentication when talking to a InfluxDB 1.8.x without authentication but is accessed via reverse proxy with basic authentication (defaults to false) - ``INFLUXDB_V2_PROFILERS`` - set the list of enabled `Flux profilers `_ diff --git a/influxdb_client/_async/rest.py b/influxdb_client/_async/rest.py index dcf678d0..da6cbbc0 100644 --- a/influxdb_client/_async/rest.py +++ b/influxdb_client/_async/rest.py @@ -83,15 +83,19 @@ def __init__(self, configuration, pools_size=4, maxsize=None, **kwargs): if maxsize is None: maxsize = configuration.connection_pool_maxsize - ssl_context = ssl.create_default_context(cafile=configuration.ssl_ca_cert) - if configuration.cert_file: - ssl_context.load_cert_chain( - configuration.cert_file, keyfile=configuration.key_file - ) - - if not configuration.verify_ssl: - ssl_context.check_hostname = False - ssl_context.verify_mode = ssl.CERT_NONE + if configuration.ssl_context is None: + ssl_context = ssl.create_default_context(cafile=configuration.ssl_ca_cert) + if configuration.cert_file: + ssl_context.load_cert_chain( + certfile=configuration.cert_file, keyfile=configuration.key_file, + password=configuration.key_password + ) + + if not configuration.verify_ssl: + ssl_context.check_hostname = False + ssl_context.verify_mode = ssl.CERT_NONE + else: + ssl_context = configuration.ssl_context connector = aiohttp.TCPConnector( limit=maxsize, diff --git a/influxdb_client/_sync/rest.py b/influxdb_client/_sync/rest.py index d3ac55c6..39beb07f 100644 --- a/influxdb_client/_sync/rest.py +++ b/influxdb_client/_sync/rest.py @@ -93,6 +93,8 @@ def __init__(self, configuration, pools_size=4, maxsize=None, retries=False): else: maxsize = 4 + # TODO Test the context option + # https pool manager if configuration.proxy: self.pool_manager = urllib3.ProxyManager( @@ -102,8 +104,10 @@ def __init__(self, configuration, pools_size=4, maxsize=None, retries=False): ca_certs=ca_certs, cert_file=configuration.cert_file, key_file=configuration.key_file, + key_password=configuration.key_password, proxy_url=configuration.proxy, proxy_headers=configuration.proxy_headers, + ssl_context=configuration.ssl_context, **addition_pool_args ) else: @@ -114,6 +118,8 @@ def __init__(self, configuration, pools_size=4, maxsize=None, retries=False): ca_certs=ca_certs, cert_file=configuration.cert_file, key_file=configuration.key_file, + key_password=configuration.key_password, + ssl_context=configuration.ssl_context, **addition_pool_args ) diff --git a/influxdb_client/client/_base.py b/influxdb_client/client/_base.py index 95aef3db..2c100241 100644 --- a/influxdb_client/client/_base.py +++ b/influxdb_client/client/_base.py @@ -60,6 +60,10 @@ def __init__(self, url, token, debug=None, timeout=10_000, enable_gzip=False, or self.conf.enable_gzip = enable_gzip self.conf.verify_ssl = kwargs.get('verify_ssl', True) self.conf.ssl_ca_cert = kwargs.get('ssl_ca_cert', None) + self.conf.cert_file = kwargs.get('cert_file', None) + self.conf.key_file = kwargs.get('key_file', None) + self.conf.key_password = kwargs.get('key_password', None) + self.conf.ssl_context = kwargs.get('ssl_context', None) self.conf.proxy = kwargs.get('proxy', None) self.conf.proxy_headers = kwargs.get('proxy_headers', None) self.conf.connection_pool_maxsize = kwargs.get('connection_pool_maxsize', self.conf.connection_pool_maxsize) @@ -142,6 +146,18 @@ def _has_section(key: str): if _has_option('ssl_ca_cert'): ssl_ca_cert = _config_value('ssl_ca_cert') + cert_file = None + if _has_option('cert_file'): + cert_file = _config_value('cert_file') + + key_file = None + if _has_option('key_file'): + key_file = _config_value('key_file') + + key_password = None + if _has_option('key_password'): + key_password = _config_value('key_password') + connection_pool_maxsize = None if _has_option('connection_pool_maxsize'): connection_pool_maxsize = _config_value('connection_pool_maxsize') @@ -168,6 +184,7 @@ def _has_section(key: str): return cls(url, token, debug=debug, timeout=_to_int(timeout), org=org, default_tags=default_tags, enable_gzip=enable_gzip, verify_ssl=_to_bool(verify_ssl), ssl_ca_cert=ssl_ca_cert, + cert_file=cert_file, key_file=key_file, key_password=key_password, connection_pool_maxsize=_to_int(connection_pool_maxsize), auth_basic=_to_bool(auth_basic), profilers=profilers, proxy=proxy, **kwargs) @@ -179,6 +196,9 @@ def _from_env_properties(cls, debug=None, enable_gzip=False, **kwargs): org = os.getenv('INFLUXDB_V2_ORG', "my-org") verify_ssl = os.getenv('INFLUXDB_V2_VERIFY_SSL', "True") ssl_ca_cert = os.getenv('INFLUXDB_V2_SSL_CA_CERT', None) + cert_file = os.getenv('INFLUXDB_V2_CERT_FILE', None) + key_file = os.getenv('INFLUXDB_V2_KEY_FILE', None) + key_password = os.getenv('INFLUXDB_V2_KEY_PASSWORD', None) connection_pool_maxsize = os.getenv('INFLUXDB_V2_CONNECTION_POOL_MAXSIZE', None) auth_basic = os.getenv('INFLUXDB_V2_AUTH_BASIC', "False") @@ -195,6 +215,7 @@ def _from_env_properties(cls, debug=None, enable_gzip=False, **kwargs): return cls(url, token, debug=debug, timeout=_to_int(timeout), org=org, default_tags=default_tags, enable_gzip=enable_gzip, verify_ssl=_to_bool(verify_ssl), ssl_ca_cert=ssl_ca_cert, + cert_file=cert_file, key_file=key_file, key_password=key_password, connection_pool_maxsize=_to_int(connection_pool_maxsize), auth_basic=_to_bool(auth_basic), profilers=profilers, **kwargs) diff --git a/influxdb_client/client/influxdb_client.py b/influxdb_client/client/influxdb_client.py index 042087da..6941aedd 100644 --- a/influxdb_client/client/influxdb_client.py +++ b/influxdb_client/client/influxdb_client.py @@ -102,6 +102,9 @@ def from_config_file(cls, config_file: str = "config.ini", debug=None, enable_gz - timeout, - verify_ssl - ssl_ca_cert + - cert_file + - key_file + - key_password - connection_pool_maxsize - auth_basic - profilers @@ -185,6 +188,9 @@ def from_env_properties(cls, debug=None, enable_gzip=False, **kwargs): - INFLUXDB_V2_TIMEOUT - INFLUXDB_V2_VERIFY_SSL - INFLUXDB_V2_SSL_CA_CERT + - INFLUXDB_V2_CERT_FILE + - INFLUXDB_V2_KEY_FILE + - INFLUXDB_V2_KEY_PASSWORD - INFLUXDB_V2_CONNECTION_POOL_MAXSIZE - INFLUXDB_V2_AUTH_BASIC - INFLUXDB_V2_PROFILERS diff --git a/influxdb_client/client/influxdb_client_async.py b/influxdb_client/client/influxdb_client_async.py index cdd8eade..d7369a66 100644 --- a/influxdb_client/client/influxdb_client_async.py +++ b/influxdb_client/client/influxdb_client_async.py @@ -201,6 +201,9 @@ def from_env_properties(cls, debug=None, enable_gzip=False, **kwargs): - INFLUXDB_V2_TIMEOUT - INFLUXDB_V2_VERIFY_SSL - INFLUXDB_V2_SSL_CA_CERT + - INFLUXDB_V2_CERT_FILE + - INFLUXDB_V2_KEY_FILE + - INFLUXDB_V2_KEY_PASSWORD - INFLUXDB_V2_CONNECTION_POOL_MAXSIZE - INFLUXDB_V2_AUTH_BASIC - INFLUXDB_V2_PROFILERS diff --git a/influxdb_client/configuration.py b/influxdb_client/configuration.py index e9d95c78..aedcf17b 100644 --- a/influxdb_client/configuration.py +++ b/influxdb_client/configuration.py @@ -90,9 +90,14 @@ def __init__(self): self.cert_file = None # client key file self.key_file = None + # client key file password + self.key_password = None # Set this to True/False to enable/disable SSL hostname verification. self.assert_hostname = None + # Set this to specify a custom ssl context to inject this context inside the urllib3 connection pool. + self.ssl_context = None + # urllib3 connection pool's maximum number of connections saved # per pool. urllib3 uses 1 connection as default value, but this is # not the best value when you are making a lot of possibly parallel From cbcc7d160af1d84aef82559d704286d4faba7f48 Mon Sep 17 00:00:00 2001 From: Pascal Zimmermann Date: Fri, 7 Oct 2022 15:22:34 +0200 Subject: [PATCH 2/6] feat: Add new unittests --- tests/config-ssl-mtls-certs.ini | 14 +++++++ tests/test_InfluxDBClient.py | 69 +++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 tests/config-ssl-mtls-certs.ini diff --git a/tests/config-ssl-mtls-certs.ini b/tests/config-ssl-mtls-certs.ini new file mode 100644 index 00000000..637e2f7f --- /dev/null +++ b/tests/config-ssl-mtls-certs.ini @@ -0,0 +1,14 @@ +[influx2] +url=http://localhost:8086 +org=my-org +token=my-token +timeout=6000 +ssl_ca_cert=/path/to/my/cert +cert_file=/path/to/my/cert +key_file=/path/to/my/key +key_password=test + +[tags] +id = 132-987-655 +customer = California Miner +data_center = ${env.data_center} \ No newline at end of file diff --git a/tests/test_InfluxDBClient.py b/tests/test_InfluxDBClient.py index c4b9b2a5..d807ca4a 100644 --- a/tests/test_InfluxDBClient.py +++ b/tests/test_InfluxDBClient.py @@ -141,6 +141,75 @@ def test_init_from_env_ssl_ca_cert(self): self.assertEqual("/my/custom/path/to/cert", self.client.api_client.configuration.ssl_ca_cert) + def test_init_from_env_ssl_cert_file(self): + os.environ["INFLUXDB_V2_CERT_FILE"] = "/my/custom/path" + self.client = InfluxDBClient.from_env_properties() + + self.assertEqual("/my/custom/path", self.client.api_client.configuration.cert_file) + + def test_init_from_file_ssl_cert_file_default(self): + self.client = InfluxDBClient.from_config_file(f'{os.path.dirname(__file__)}/config.ini') + + self.assertIsNone(self.client.api_client.configuration.cert_file) + + def test_init_from_file_ssl_cert_file(self): + self.client = InfluxDBClient.from_config_file(f'{os.path.dirname(__file__)}/config-ssl-mtls-certs.ini') + + self.assertEqual("/path/to/my/cert", self.client.api_client.configuration.cert_file) + + def test_init_from_env_ssl_cert_file_default(self): + if os.getenv("INFLUXDB_V2_CERT_FILE"): + del os.environ["INFLUXDB_V2_CERT_FILE"] + self.client = InfluxDBClient.from_env_properties() + + self.assertIsNone(self.client.api_client.configuration.cert_file) + + def test_init_from_env_ssl_cert_key(self): + os.environ["INFLUXDB_V2_KEY_FILE"] = "/my/custom/path" + self.client = InfluxDBClient.from_env_properties() + + self.assertEqual("/my/custom/path", self.client.api_client.configuration.key_file) + + def test_init_from_file_ssl_cert_key_default(self): + self.client = InfluxDBClient.from_config_file(f'{os.path.dirname(__file__)}/config.ini') + + self.assertIsNone(self.client.api_client.configuration.key_file) + + def test_init_from_file_ssl_cert_key(self): + self.client = InfluxDBClient.from_config_file(f'{os.path.dirname(__file__)}/config-ssl-mtls-certs.ini') + + self.assertEqual("/path/to/my/key", self.client.api_client.configuration.key_file) + + def test_init_from_env_ssl_cert_key_default(self): + if os.getenv("INFLUXDB_V2_KEY_FILE"): + del os.environ["INFLUXDB_V2_KEY_FILE"] + self.client = InfluxDBClient.from_env_properties() + + self.assertIsNone(self.client.api_client.configuration.key_file) + + def test_init_from_env_ssl_key_password(self): + os.environ["INFLUXDB_V2_KEY_PASSWORD"] = "test" + self.client = InfluxDBClient.from_env_properties() + + self.assertEqual("test", self.client.api_client.configuration.key_password) + + def test_init_from_file_ssl_key_password_default(self): + self.client = InfluxDBClient.from_config_file(f'{os.path.dirname(__file__)}/config.ini') + + self.assertIsNone(self.client.api_client.configuration.key_password) + + def test_init_from_file_ssl_key_password(self): + self.client = InfluxDBClient.from_config_file(f'{os.path.dirname(__file__)}/config-ssl-mtls-certs.ini') + + self.assertEqual("test", self.client.api_client.configuration.key_password) + + def test_init_from_env_ssl_key_password_default(self): + if os.getenv("INFLUXDB_V2_KEY_PASSWORD"): + del os.environ["INFLUXDB_V2_KEY_PASSWORD"] + self.client = InfluxDBClient.from_env_properties() + + self.assertIsNone(self.client.api_client.configuration.key_password) + def test_init_from_env_connection_pool_maxsize(self): os.environ["INFLUXDB_V2_CONNECTION_POOL_MAXSIZE"] = "29" self.client = InfluxDBClient.from_env_properties() From 9fdf2cbb001c8d9a0a0c463dbd0157a9cc17f935 Mon Sep 17 00:00:00 2001 From: Pascal Zimmermann Date: Fri, 7 Oct 2022 15:34:40 +0200 Subject: [PATCH 3/6] feat: Add a specific tls context test case --- influxdb_client/_sync/rest.py | 2 -- tests/test_InfluxDBClient.py | 13 +++++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/influxdb_client/_sync/rest.py b/influxdb_client/_sync/rest.py index 39beb07f..c2f8de4b 100644 --- a/influxdb_client/_sync/rest.py +++ b/influxdb_client/_sync/rest.py @@ -93,8 +93,6 @@ def __init__(self, configuration, pools_size=4, maxsize=None, retries=False): else: maxsize = 4 - # TODO Test the context option - # https pool manager if configuration.proxy: self.pool_manager = urllib3.ProxyManager( diff --git a/tests/test_InfluxDBClient.py b/tests/test_InfluxDBClient.py index d807ca4a..39ed417c 100644 --- a/tests/test_InfluxDBClient.py +++ b/tests/test_InfluxDBClient.py @@ -3,6 +3,7 @@ import json import logging import os +import ssl import threading import unittest from io import StringIO @@ -57,6 +58,18 @@ def test_certificate_file(self): self.assertTrue(ping) + def test_certificate_context(self): + self._start_http_server() + + ssl_context = ssl.create_default_context(cafile=f"{os.path.dirname(__file__)}/server.pem") + + self.client = InfluxDBClient(f"https://localhost:{self.httpd.server_address[1]}", + token="my-token", verify_ssl=True, + ssl_context=ssl_context) + ping = self.client.ping() + + self.assertTrue(ping) + def test_init_from_ini_file(self): self.client = InfluxDBClient.from_config_file(f'{os.path.dirname(__file__)}/config.ini') From c7fee74269e63662dec3bb07ab5f47dca59d22ef Mon Sep 17 00:00:00 2001 From: Pascal Zimmermann Date: Tue, 11 Oct 2022 20:27:23 +0200 Subject: [PATCH 4/6] feat: Update the documentation and rename the MTLS variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BREAKING CHANGE: Rename `key_file` to `cert_key_file` inside the central configuration class Co-authored-by: Jakub Bednář --- CHANGELOG.md | 3 ++ README.rst | 12 ++++---- influxdb_client/_async/rest.py | 4 +-- influxdb_client/_sync/rest.py | 8 ++--- influxdb_client/client/_base.py | 24 +++++++-------- influxdb_client/client/influxdb_client.py | 30 ++++++++++++++++--- .../client/influxdb_client_async.py | 30 +++++++++++++++++-- influxdb_client/configuration.py | 4 +-- tests/config-ssl-mtls-certs.ini | 4 +-- tests/test_InfluxDBClient.py | 28 ++++++++--------- 10 files changed, 99 insertions(+), 48 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45448b75..49414822 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ ### Bug Fixes 1. [#512](https://github.com/influxdata/influxdb-client-python/pull/512): Exception propagation for asynchronous `QueryApi` [async/await] +### Breaking Changes +1. [#509](https://github.com/influxdata/influxdb-client-python/pull/509): Rename `key_file` to `cert_key_file` inside the central [configuration class](https://github.com/influxdata/influxdb-client-python/blob/d011df72b528a45d305aa8accbe879b31be3280e/influxdb_client/configuration.py#L92) + ## 1.33.0 [2022-09-29] ### Features diff --git a/README.rst b/README.rst index 66bc2186..88e05c16 100644 --- a/README.rst +++ b/README.rst @@ -197,9 +197,9 @@ The following options are supported: - ``timeout`` - socket timeout in ms (default value is 10000) - ``verify_ssl`` - set this to false to skip verifying SSL certificate when calling API from https server - ``ssl_ca_cert`` - set this to customize the certificate file to verify the peer -- ``cert_file`` - set this to customize the certificate client certificate file -- ``key_file`` - set this to customize the certificate client key file -- ``key_password`` - set this to customize the certificate client key file password +- ``cert_file`` - path to the certificate that will be used for mTLS authentication +- ``cert_key_file`` - path to the file contains private key for mTLS certificate +- ``cert_key_password`` - string or function which returns password for decrypting the mTLS private key - ``connection_pool_maxsize`` - set the number of connections to save that can be reused by urllib3 - ``auth_basic`` - enable http basic authentication when talking to a InfluxDB 1.8.x without authentication but is accessed via reverse proxy with basic authentication (defaults to false) - ``profilers`` - set the list of enabled `Flux profilers `_ @@ -229,9 +229,9 @@ Supported properties are: - ``INFLUXDB_V2_TIMEOUT`` - socket timeout in ms (default value is 10000) - ``INFLUXDB_V2_VERIFY_SSL`` - set this to false to skip verifying SSL certificate when calling API from https server - ``INFLUXDB_V2_SSL_CA_CERT`` - set this to customize the certificate file to verify the peer -- ``INFLUXDB_V2_CERT_FILE`` - set this to customize the certificate client certificate file -- ``INFLUXDB_V2_KEY_FILE`` - set this to customize the certificate client key file -- ``INFLUXDB_V2_KEY_PASSWORD`` - set this to customize the certificate client key file password +- ``INFLUXDB_V2_CERT_FILE`` - path to the certificate that will be used for mTLS authentication +- ``INFLUXDB_V2_CERT_KEY_FILE`` - path to the file contains private key for mTLS certificate +- ``INFLUXDB_V2_CERT_KEY_PASSWORD`` - string or function which returns password for decrypting the mTLS private key - ``INFLUXDB_V2_CONNECTION_POOL_MAXSIZE`` - set the number of connections to save that can be reused by urllib3 - ``INFLUXDB_V2_AUTH_BASIC`` - enable http basic authentication when talking to a InfluxDB 1.8.x without authentication but is accessed via reverse proxy with basic authentication (defaults to false) - ``INFLUXDB_V2_PROFILERS`` - set the list of enabled `Flux profilers `_ diff --git a/influxdb_client/_async/rest.py b/influxdb_client/_async/rest.py index da6cbbc0..8db95e91 100644 --- a/influxdb_client/_async/rest.py +++ b/influxdb_client/_async/rest.py @@ -87,8 +87,8 @@ def __init__(self, configuration, pools_size=4, maxsize=None, **kwargs): ssl_context = ssl.create_default_context(cafile=configuration.ssl_ca_cert) if configuration.cert_file: ssl_context.load_cert_chain( - certfile=configuration.cert_file, keyfile=configuration.key_file, - password=configuration.key_password + certfile=configuration.cert_file, keyfile=configuration.cert_key_file, + password=configuration.cert_key_password ) if not configuration.verify_ssl: diff --git a/influxdb_client/_sync/rest.py b/influxdb_client/_sync/rest.py index c2f8de4b..bac94f9e 100644 --- a/influxdb_client/_sync/rest.py +++ b/influxdb_client/_sync/rest.py @@ -101,8 +101,8 @@ def __init__(self, configuration, pools_size=4, maxsize=None, retries=False): cert_reqs=cert_reqs, ca_certs=ca_certs, cert_file=configuration.cert_file, - key_file=configuration.key_file, - key_password=configuration.key_password, + key_file=configuration.cert_key_file, + key_password=configuration.cert_key_password, proxy_url=configuration.proxy, proxy_headers=configuration.proxy_headers, ssl_context=configuration.ssl_context, @@ -115,8 +115,8 @@ def __init__(self, configuration, pools_size=4, maxsize=None, retries=False): cert_reqs=cert_reqs, ca_certs=ca_certs, cert_file=configuration.cert_file, - key_file=configuration.key_file, - key_password=configuration.key_password, + key_file=configuration.cert_key_file, + key_password=configuration.cert_key_password, ssl_context=configuration.ssl_context, **addition_pool_args ) diff --git a/influxdb_client/client/_base.py b/influxdb_client/client/_base.py index 2c100241..de2910da 100644 --- a/influxdb_client/client/_base.py +++ b/influxdb_client/client/_base.py @@ -61,8 +61,8 @@ def __init__(self, url, token, debug=None, timeout=10_000, enable_gzip=False, or self.conf.verify_ssl = kwargs.get('verify_ssl', True) self.conf.ssl_ca_cert = kwargs.get('ssl_ca_cert', None) self.conf.cert_file = kwargs.get('cert_file', None) - self.conf.key_file = kwargs.get('key_file', None) - self.conf.key_password = kwargs.get('key_password', None) + self.conf.cert_key_file = kwargs.get('cert_key_file', None) + self.conf.cert_key_password = kwargs.get('cert_key_password', None) self.conf.ssl_context = kwargs.get('ssl_context', None) self.conf.proxy = kwargs.get('proxy', None) self.conf.proxy_headers = kwargs.get('proxy_headers', None) @@ -150,13 +150,13 @@ def _has_section(key: str): if _has_option('cert_file'): cert_file = _config_value('cert_file') - key_file = None - if _has_option('key_file'): - key_file = _config_value('key_file') + cert_key_file = None + if _has_option('cert_key_file'): + cert_key_file = _config_value('cert_key_file') - key_password = None - if _has_option('key_password'): - key_password = _config_value('key_password') + cert_key_password = None + if _has_option('cert_key_password'): + cert_key_password = _config_value('cert_key_password') connection_pool_maxsize = None if _has_option('connection_pool_maxsize'): @@ -184,7 +184,7 @@ def _has_section(key: str): return cls(url, token, debug=debug, timeout=_to_int(timeout), org=org, default_tags=default_tags, enable_gzip=enable_gzip, verify_ssl=_to_bool(verify_ssl), ssl_ca_cert=ssl_ca_cert, - cert_file=cert_file, key_file=key_file, key_password=key_password, + cert_file=cert_file, cert_key_file=cert_key_file, cert_key_password=cert_key_password, connection_pool_maxsize=_to_int(connection_pool_maxsize), auth_basic=_to_bool(auth_basic), profilers=profilers, proxy=proxy, **kwargs) @@ -197,8 +197,8 @@ def _from_env_properties(cls, debug=None, enable_gzip=False, **kwargs): verify_ssl = os.getenv('INFLUXDB_V2_VERIFY_SSL', "True") ssl_ca_cert = os.getenv('INFLUXDB_V2_SSL_CA_CERT', None) cert_file = os.getenv('INFLUXDB_V2_CERT_FILE', None) - key_file = os.getenv('INFLUXDB_V2_KEY_FILE', None) - key_password = os.getenv('INFLUXDB_V2_KEY_PASSWORD', None) + cert_key_file = os.getenv('INFLUXDB_V2_CERT_KEY_FILE', None) + cert_key_password = os.getenv('INFLUXDB_V2_CERT_KEY_PASSWORD', None) connection_pool_maxsize = os.getenv('INFLUXDB_V2_CONNECTION_POOL_MAXSIZE', None) auth_basic = os.getenv('INFLUXDB_V2_AUTH_BASIC', "False") @@ -215,7 +215,7 @@ def _from_env_properties(cls, debug=None, enable_gzip=False, **kwargs): return cls(url, token, debug=debug, timeout=_to_int(timeout), org=org, default_tags=default_tags, enable_gzip=enable_gzip, verify_ssl=_to_bool(verify_ssl), ssl_ca_cert=ssl_ca_cert, - cert_file=cert_file, key_file=key_file, key_password=key_password, + cert_file=cert_file, cert_key_file=cert_key_file, cert_key_password=cert_key_password, connection_pool_maxsize=_to_int(connection_pool_maxsize), auth_basic=_to_bool(auth_basic), profilers=profilers, **kwargs) diff --git a/influxdb_client/client/influxdb_client.py b/influxdb_client/client/influxdb_client.py index 6941aedd..ff45ff73 100644 --- a/influxdb_client/client/influxdb_client.py +++ b/influxdb_client/client/influxdb_client.py @@ -40,6 +40,12 @@ def __init__(self, url, token: str = None, debug=None, timeout=10_000, enable_gz :param org: organization name (used as a default in Query, Write and Delete API) :key bool verify_ssl: Set this to false to skip verifying SSL certificate when calling API from https server. :key str ssl_ca_cert: Set this to customize the certificate file to verify the peer. + :key str cert_file: Path to the certificate that will be used for mTLS authentication. + :key str cert_key_file: Path to the file contains private key for mTLS certificate. + :key str cert_key_password: String or function which returns password for decrypting the mTLS private key. + :key ssl.SSLContext ssl_context: Specify a custom Python SSL Context for the TLS/ mTLS handshake. + Be aware that only delivered certificate/ key files or an SSL Context are + possible. :key str proxy: Set this to configure the http proxy to be used (ex. http://localhost:3128) :key str proxy_headers: A dictionary containing headers that will be sent to the proxy. Could be used for proxy authentication. @@ -89,6 +95,14 @@ def from_config_file(cls, config_file: str = "config.ini", debug=None, enable_gz authentication. :key urllib3.util.retry.Retry retries: Set the default retry strategy that is used for all HTTP requests except batching writes. As a default there is no one retry strategy. + :key bool verify_ssl: Set this to false to skip verifying SSL certificate when calling API from https server. + :key str ssl_ca_cert: Set this to customize the certificate file to verify the peer. + :key str cert_file: Path to the certificate that will be used for mTLS authentication. + :key str cert_key_file: Path to the file contains private key for mTLS certificate. + :key str cert_key_password: String or function which returns password for decrypting the mTLS private key. + :key ssl.SSLContext ssl_context: Specify a custom Python SSL Context for the TLS/ mTLS handshake. + Be aware that only delivered certificate/ key files or an SSL Context are + possible. The supported formats: - https://docs.python.org/3/library/configparser.html @@ -103,8 +117,8 @@ def from_config_file(cls, config_file: str = "config.ini", debug=None, enable_gz - verify_ssl - ssl_ca_cert - cert_file - - key_file - - key_password + - cert_key_file + - cert_key_password - connection_pool_maxsize - auth_basic - profilers @@ -180,6 +194,14 @@ def from_env_properties(cls, debug=None, enable_gzip=False, **kwargs): authentication. :key urllib3.util.retry.Retry retries: Set the default retry strategy that is used for all HTTP requests except batching writes. As a default there is no one retry strategy. + :key bool verify_ssl: Set this to false to skip verifying SSL certificate when calling API from https server. + :key str ssl_ca_cert: Set this to customize the certificate file to verify the peer. + :key str cert_file: Path to the certificate that will be used for mTLS authentication. + :key str cert_key_file: Path to the file contains private key for mTLS certificate. + :key str cert_key_password: String or function which returns password for decrypting the mTLS private key. + :key ssl.SSLContext ssl_context: Specify a custom Python SSL Context for the TLS/ mTLS handshake. + Be aware that only delivered certificate/ key files or an SSL Context are + possible. Supported environment properties: - INFLUXDB_V2_URL @@ -189,8 +211,8 @@ def from_env_properties(cls, debug=None, enable_gzip=False, **kwargs): - INFLUXDB_V2_VERIFY_SSL - INFLUXDB_V2_SSL_CA_CERT - INFLUXDB_V2_CERT_FILE - - INFLUXDB_V2_KEY_FILE - - INFLUXDB_V2_KEY_PASSWORD + - INFLUXDB_V2_CERT_KEY_FILE + - INFLUXDB_V2_CERT_KEY_PASSWORD - INFLUXDB_V2_CONNECTION_POOL_MAXSIZE - INFLUXDB_V2_AUTH_BASIC - INFLUXDB_V2_PROFILERS diff --git a/influxdb_client/client/influxdb_client_async.py b/influxdb_client/client/influxdb_client_async.py index d7369a66..ba51a7f4 100644 --- a/influxdb_client/client/influxdb_client_async.py +++ b/influxdb_client/client/influxdb_client_async.py @@ -32,6 +32,12 @@ def __init__(self, url, token: str = None, org: str = None, debug=None, timeout= supports the Gzip compression. :key bool verify_ssl: Set this to false to skip verifying SSL certificate when calling API from https server. :key str ssl_ca_cert: Set this to customize the certificate file to verify the peer. + :key str cert_file: Path to the certificate that will be used for mTLS authentication. + :key str cert_key_file: Path to the file contains private key for mTLS certificate. + :key str cert_key_password: String or function which returns password for decrypting the mTLS private key. + :key ssl.SSLContext ssl_context: Specify a custom Python SSL Context for the TLS/ mTLS handshake. + Be aware that only delivered certificate/ key files or an SSL Context are + possible. :key str proxy: Set this to configure the http proxy to be used (ex. http://localhost:3128) :key str proxy_headers: A dictionary containing headers that will be sent to the proxy. Could be used for proxy authentication. @@ -105,6 +111,14 @@ def from_config_file(cls, config_file: str = "config.ini", debug=None, enable_gz authentication. :key urllib3.util.retry.Retry retries: Set the default retry strategy that is used for all HTTP requests except batching writes. As a default there is no one retry strategy. + :key bool verify_ssl: Set this to false to skip verifying SSL certificate when calling API from https server. + :key str ssl_ca_cert: Set this to customize the certificate file to verify the peer. + :key str cert_file: Path to the certificate that will be used for mTLS authentication. + :key str cert_key_file: Path to the file contains private key for mTLS certificate. + :key str cert_key_password: String or function which returns password for decrypting the mTLS private key. + :key ssl.SSLContext ssl_context: Specify a custom Python SSL Context for the TLS/ mTLS handshake. + Be aware that only delivered certificate/ key files or an SSL Context are + possible. The supported formats: - https://docs.python.org/3/library/configparser.html @@ -118,6 +132,9 @@ def from_config_file(cls, config_file: str = "config.ini", debug=None, enable_gz - timeout, - verify_ssl - ssl_ca_cert + - cert_file + - cert_key_file + - cert_key_password - connection_pool_maxsize - auth_basic - profilers @@ -193,6 +210,15 @@ def from_env_properties(cls, debug=None, enable_gzip=False, **kwargs): authentication. :key urllib3.util.retry.Retry retries: Set the default retry strategy that is used for all HTTP requests except batching writes. As a default there is no one retry strategy. + :key bool verify_ssl: Set this to false to skip verifying SSL certificate when calling API from https server. + :key str ssl_ca_cert: Set this to customize the certificate file to verify the peer. + :key str cert_file: Path to the certificate that will be used for mTLS authentication. + :key str cert_key_file: Path to the file contains private key for mTLS certificate. + :key str cert_key_password: String or function which returns password for decrypting the mTLS private key. + :key ssl.SSLContext ssl_context: Specify a custom Python SSL Context for the TLS/ mTLS handshake. + Be aware that only delivered certificate/ key files or an SSL Context are + possible. + Supported environment properties: - INFLUXDB_V2_URL @@ -202,8 +228,8 @@ def from_env_properties(cls, debug=None, enable_gzip=False, **kwargs): - INFLUXDB_V2_VERIFY_SSL - INFLUXDB_V2_SSL_CA_CERT - INFLUXDB_V2_CERT_FILE - - INFLUXDB_V2_KEY_FILE - - INFLUXDB_V2_KEY_PASSWORD + - INFLUXDB_V2_CERT_KEY_FILE + - INFLUXDB_V2_CERT_KEY_PASSWORD - INFLUXDB_V2_CONNECTION_POOL_MAXSIZE - INFLUXDB_V2_AUTH_BASIC - INFLUXDB_V2_PROFILERS diff --git a/influxdb_client/configuration.py b/influxdb_client/configuration.py index aedcf17b..3c118565 100644 --- a/influxdb_client/configuration.py +++ b/influxdb_client/configuration.py @@ -89,9 +89,9 @@ def __init__(self): # client certificate file self.cert_file = None # client key file - self.key_file = None + self.cert_key_file = None # client key file password - self.key_password = None + self.cert_key_password = None # Set this to True/False to enable/disable SSL hostname verification. self.assert_hostname = None diff --git a/tests/config-ssl-mtls-certs.ini b/tests/config-ssl-mtls-certs.ini index 637e2f7f..0b3d6360 100644 --- a/tests/config-ssl-mtls-certs.ini +++ b/tests/config-ssl-mtls-certs.ini @@ -5,8 +5,8 @@ token=my-token timeout=6000 ssl_ca_cert=/path/to/my/cert cert_file=/path/to/my/cert -key_file=/path/to/my/key -key_password=test +cert_key_file=/path/to/my/key +cert_key_password=test [tags] id = 132-987-655 diff --git a/tests/test_InfluxDBClient.py b/tests/test_InfluxDBClient.py index 39ed417c..5202d7a9 100644 --- a/tests/test_InfluxDBClient.py +++ b/tests/test_InfluxDBClient.py @@ -178,50 +178,50 @@ def test_init_from_env_ssl_cert_file_default(self): self.assertIsNone(self.client.api_client.configuration.cert_file) def test_init_from_env_ssl_cert_key(self): - os.environ["INFLUXDB_V2_KEY_FILE"] = "/my/custom/path" + os.environ["INFLUXDB_V2_CERT_KEY_FILE"] = "/my/custom/path" self.client = InfluxDBClient.from_env_properties() - self.assertEqual("/my/custom/path", self.client.api_client.configuration.key_file) + self.assertEqual("/my/custom/path", self.client.api_client.configuration.cert_key_file) def test_init_from_file_ssl_cert_key_default(self): self.client = InfluxDBClient.from_config_file(f'{os.path.dirname(__file__)}/config.ini') - self.assertIsNone(self.client.api_client.configuration.key_file) + self.assertIsNone(self.client.api_client.configuration.cert_key_file) def test_init_from_file_ssl_cert_key(self): self.client = InfluxDBClient.from_config_file(f'{os.path.dirname(__file__)}/config-ssl-mtls-certs.ini') - self.assertEqual("/path/to/my/key", self.client.api_client.configuration.key_file) + self.assertEqual("/path/to/my/key", self.client.api_client.configuration.cert_key_file) def test_init_from_env_ssl_cert_key_default(self): - if os.getenv("INFLUXDB_V2_KEY_FILE"): - del os.environ["INFLUXDB_V2_KEY_FILE"] + if os.getenv("INFLUXDB_V2_CERT_KEY_FILE"): + del os.environ["INFLUXDB_V2_CERT_KEY_FILE"] self.client = InfluxDBClient.from_env_properties() - self.assertIsNone(self.client.api_client.configuration.key_file) + self.assertIsNone(self.client.api_client.configuration.cert_key_file) def test_init_from_env_ssl_key_password(self): - os.environ["INFLUXDB_V2_KEY_PASSWORD"] = "test" + os.environ["INFLUXDB_V2_CERT_KEY_PASSWORD"] = "test" self.client = InfluxDBClient.from_env_properties() - self.assertEqual("test", self.client.api_client.configuration.key_password) + self.assertEqual("test", self.client.api_client.configuration.cert_key_password) def test_init_from_file_ssl_key_password_default(self): self.client = InfluxDBClient.from_config_file(f'{os.path.dirname(__file__)}/config.ini') - self.assertIsNone(self.client.api_client.configuration.key_password) + self.assertIsNone(self.client.api_client.configuration.cert_key_password) def test_init_from_file_ssl_key_password(self): self.client = InfluxDBClient.from_config_file(f'{os.path.dirname(__file__)}/config-ssl-mtls-certs.ini') - self.assertEqual("test", self.client.api_client.configuration.key_password) + self.assertEqual("test", self.client.api_client.configuration.cert_key_password) def test_init_from_env_ssl_key_password_default(self): - if os.getenv("INFLUXDB_V2_KEY_PASSWORD"): - del os.environ["INFLUXDB_V2_KEY_PASSWORD"] + if os.getenv("INFLUXDB_V2_CERT_KEY_PASSWORD"): + del os.environ["INFLUXDB_V2_CERT_KEY_PASSWORD"] self.client = InfluxDBClient.from_env_properties() - self.assertIsNone(self.client.api_client.configuration.key_password) + self.assertIsNone(self.client.api_client.configuration.cert_key_password) def test_init_from_env_connection_pool_maxsize(self): os.environ["INFLUXDB_V2_CONNECTION_POOL_MAXSIZE"] = "29" From dea0a56d09efd2bdc2148658babb5d2cfda55994 Mon Sep 17 00:00:00 2001 From: Pascal Zimmermann Date: Thu, 13 Oct 2022 20:54:18 +0200 Subject: [PATCH 5/6] docs: Update the docstring documentation --- influxdb_client/client/influxdb_client.py | 10 ---------- influxdb_client/client/influxdb_client_async.py | 10 ---------- 2 files changed, 20 deletions(-) diff --git a/influxdb_client/client/influxdb_client.py b/influxdb_client/client/influxdb_client.py index ff45ff73..91030774 100644 --- a/influxdb_client/client/influxdb_client.py +++ b/influxdb_client/client/influxdb_client.py @@ -95,11 +95,6 @@ def from_config_file(cls, config_file: str = "config.ini", debug=None, enable_gz authentication. :key urllib3.util.retry.Retry retries: Set the default retry strategy that is used for all HTTP requests except batching writes. As a default there is no one retry strategy. - :key bool verify_ssl: Set this to false to skip verifying SSL certificate when calling API from https server. - :key str ssl_ca_cert: Set this to customize the certificate file to verify the peer. - :key str cert_file: Path to the certificate that will be used for mTLS authentication. - :key str cert_key_file: Path to the file contains private key for mTLS certificate. - :key str cert_key_password: String or function which returns password for decrypting the mTLS private key. :key ssl.SSLContext ssl_context: Specify a custom Python SSL Context for the TLS/ mTLS handshake. Be aware that only delivered certificate/ key files or an SSL Context are possible. @@ -194,11 +189,6 @@ def from_env_properties(cls, debug=None, enable_gzip=False, **kwargs): authentication. :key urllib3.util.retry.Retry retries: Set the default retry strategy that is used for all HTTP requests except batching writes. As a default there is no one retry strategy. - :key bool verify_ssl: Set this to false to skip verifying SSL certificate when calling API from https server. - :key str ssl_ca_cert: Set this to customize the certificate file to verify the peer. - :key str cert_file: Path to the certificate that will be used for mTLS authentication. - :key str cert_key_file: Path to the file contains private key for mTLS certificate. - :key str cert_key_password: String or function which returns password for decrypting the mTLS private key. :key ssl.SSLContext ssl_context: Specify a custom Python SSL Context for the TLS/ mTLS handshake. Be aware that only delivered certificate/ key files or an SSL Context are possible. diff --git a/influxdb_client/client/influxdb_client_async.py b/influxdb_client/client/influxdb_client_async.py index ba51a7f4..96953cb3 100644 --- a/influxdb_client/client/influxdb_client_async.py +++ b/influxdb_client/client/influxdb_client_async.py @@ -111,11 +111,6 @@ def from_config_file(cls, config_file: str = "config.ini", debug=None, enable_gz authentication. :key urllib3.util.retry.Retry retries: Set the default retry strategy that is used for all HTTP requests except batching writes. As a default there is no one retry strategy. - :key bool verify_ssl: Set this to false to skip verifying SSL certificate when calling API from https server. - :key str ssl_ca_cert: Set this to customize the certificate file to verify the peer. - :key str cert_file: Path to the certificate that will be used for mTLS authentication. - :key str cert_key_file: Path to the file contains private key for mTLS certificate. - :key str cert_key_password: String or function which returns password for decrypting the mTLS private key. :key ssl.SSLContext ssl_context: Specify a custom Python SSL Context for the TLS/ mTLS handshake. Be aware that only delivered certificate/ key files or an SSL Context are possible. @@ -210,11 +205,6 @@ def from_env_properties(cls, debug=None, enable_gzip=False, **kwargs): authentication. :key urllib3.util.retry.Retry retries: Set the default retry strategy that is used for all HTTP requests except batching writes. As a default there is no one retry strategy. - :key bool verify_ssl: Set this to false to skip verifying SSL certificate when calling API from https server. - :key str ssl_ca_cert: Set this to customize the certificate file to verify the peer. - :key str cert_file: Path to the certificate that will be used for mTLS authentication. - :key str cert_key_file: Path to the file contains private key for mTLS certificate. - :key str cert_key_password: String or function which returns password for decrypting the mTLS private key. :key ssl.SSLContext ssl_context: Specify a custom Python SSL Context for the TLS/ mTLS handshake. Be aware that only delivered certificate/ key files or an SSL Context are possible. From ab43523d275e7f7fde2f94a3b19f9c836953f18d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Bedn=C3=A1=C5=99?= Date: Fri, 14 Oct 2022 13:54:48 +0200 Subject: [PATCH 6/6] docs: update CHANGELOG.md --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49414822..4723457e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## 1.34.0 [unreleased] +### Breaking Changes +1. [#509](https://github.com/influxdata/influxdb-client-python/pull/509): Rename `key_file` to `cert_key_file` inside the central [configuration class](https://github.com/influxdata/influxdb-client-python/blob/d011df72b528a45d305aa8accbe879b31be3280e/influxdb_client/configuration.py#L92) + ### Features 1. [#510](https://github.com/influxdata/influxdb-client-python/pull/510): Allow to use client's optional configs for initialization from file or environment properties 2. [#509](https://github.com/influxdata/influxdb-client-python/pull/509): MTLS support for the InfluxDB Python client @@ -7,9 +10,6 @@ ### Bug Fixes 1. [#512](https://github.com/influxdata/influxdb-client-python/pull/512): Exception propagation for asynchronous `QueryApi` [async/await] -### Breaking Changes -1. [#509](https://github.com/influxdata/influxdb-client-python/pull/509): Rename `key_file` to `cert_key_file` inside the central [configuration class](https://github.com/influxdata/influxdb-client-python/blob/d011df72b528a45d305aa8accbe879b31be3280e/influxdb_client/configuration.py#L92) - ## 1.33.0 [2022-09-29] ### Features