Skip to content

Commit

Permalink
HL Python SDK: Fix Client SSL configuration (#7516)
Browse files Browse the repository at this point in the history
  • Loading branch information
N-o-Z authored Feb 26, 2024
1 parent ac23b20 commit e362578
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 13 deletions.
4 changes: 2 additions & 2 deletions clients/python-wrapper/lakefs/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@ class Client:

def __init__(self, **kwargs):
self._conf = ClientConfig(**kwargs)
self._client = LakeFSClient(self._conf.configuration, header_name='X-Lakefs-Client',
self._client = LakeFSClient(self._conf, header_name='X-Lakefs-Client',
header_value='python-lakefs')

@property
def config(self):
"""
Return the underlying lakefs_sdk configuration
"""
return self._conf.configuration
return self._conf

@property
def sdk_client(self):
Expand Down
21 changes: 13 additions & 8 deletions clients/python-wrapper/lakefs/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import os
from pathlib import Path
from typing import Optional

import yaml
from lakefs_sdk import Configuration
Expand All @@ -18,7 +19,7 @@
_LAKECTL_SECRET_ACCESS_KEY_ENV = "LAKECTL_CREDENTIALS_SECRET_ACCESS_KEY"


class ClientConfig:
class ClientConfig(Configuration):
"""
Configuration class for the SDK Client.
Instantiation will try to get authentication methods using the following chain:
Expand All @@ -45,12 +46,16 @@ class Credentials(LenientNamedTuple):
access_key_id: str
secret_access_key: str

configuration: Configuration
server: Server
credentials: Credentials

def __init__(self, **kwargs):
self.configuration = Configuration(**kwargs)
def __init__(self, verify_ssl: Optional[bool] = None, proxy: Optional[str] = None, **kwargs):
super().__init__(**kwargs)
if verify_ssl is not None:
self.verify_ssl = verify_ssl
if proxy is not None:
self.proxy = proxy

if kwargs:
return

Expand All @@ -71,10 +76,10 @@ def __init__(self, **kwargs):
key_env = os.getenv(_LAKECTL_ACCESS_KEY_ID_ENV)
secret_env = os.getenv(_LAKECTL_SECRET_ACCESS_KEY_ENV)

self.configuration.host = endpoint_env if endpoint_env is not None else self.server.endpoint_url
self.configuration.username = key_env if key_env is not None else self.credentials.access_key_id
self.configuration.password = secret_env if secret_env is not None else self.credentials.secret_access_key
if len(self.configuration.username) > 0 and len(self.configuration.password) > 0:
self.host = endpoint_env if endpoint_env is not None else self.server.endpoint_url
self.username = key_env if key_env is not None else self.credentials.access_key_id
self.password = secret_env if secret_env is not None else self.credentials.secret_access_key
if len(self.username) > 0 and len(self.password) > 0:
found = True

# TODO: authentication via IAM Role
Expand Down
17 changes: 17 additions & 0 deletions clients/python-wrapper/tests/integration/test_sanity.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import ssl
import time
import pytest

from tests.utests.common import expect_exception_context
from lakefs.exceptions import NotFoundException, ConflictException, ObjectNotFoundException
Expand Down Expand Up @@ -123,3 +125,18 @@ def test_object_sanity(setup_repo):
obj.delete()
with expect_exception_context(ObjectNotFoundException):
obj.stat()


@pytest.mark.parametrize("ssl_enabled", (True, False, None))
def test_ssl_configuration(ssl_enabled):
expected_ssl = ssl_enabled is not False
expected_cert_req = ssl.CERT_REQUIRED if expected_ssl else ssl.CERT_NONE
proxy = "http://someproxy:1234"
cert = "somecert"
clt = lakefs.client.Client(verify_ssl=ssl_enabled, proxy=proxy, ssl_ca_cert=cert)
assert clt.config.verify_ssl is expected_ssl
assert clt.config.proxy == proxy
assert clt.config.ssl_ca_cert == cert
assert clt.sdk_client._api.rest_client.pool_manager.connection_pool_kw.get("cert_reqs") is expected_cert_req
assert str(clt.sdk_client._api.rest_client.pool_manager.proxy) == proxy
assert clt.sdk_client._api.rest_client.pool_manager.connection_pool_kw.get("ca_certs") is cert
16 changes: 13 additions & 3 deletions docs/integrations/python.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,12 @@ clt = Client(
For testing SSL endpoints you may wish to use a self-signed certificate. If you do this and receive an `SSL: CERTIFICATE_VERIFY_FAILED` error message you might add the following configuration to your client:

```python
clt.config.verify_ssl= False
clt = Client(
host="http://localhost:8000",
username="AKIAIOSFODNN7EXAMPLE",
password="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
verify_ssl=False,
)
```

{: .warning }
Expand All @@ -70,8 +75,13 @@ production setting.
Optionally, to enable communication via proxies, simply set the proxy configuration:

```python
clt.config.ssl_ca_cert = <path to a file of concatenated CA certificates in PEM format> # Set this to customize the certificate file to verify the peer
clt.config.proxy = <proxy server URL>
clt = Client(
host="http://localhost:8000",
username="AKIAIOSFODNN7EXAMPLE",
password="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
ssl_ca_cert="<path to a file of concatenated CA certificates in PEM format>", # Set this to customize the certificate file to verify the peer
proxy="<proxy server URL>",
)
```

### Usage Examples
Expand Down

0 comments on commit e362578

Please sign in to comment.