snowflakedb/snowflake-cli

Ambiguous Private Key File Attribute, deprecate `private_key_path`

kameshsampath opened this issue · 1 comments

SnowCLI version

Snowflake CLI version: 2.5.0

Python version

Python 3.11.9

Platform

macOS-14.6.1-arm64-arm-64bit

What happened

Currently Snow CLI supports the Private Keyfile attribute used for Snowflake connection using private_key_path or private_key_file attributes in the configuration TOML. This is causing ambiguity and error when using the same config for both Snow CLI and Python Connector, as Python Connector understands only private_key_file.

Console output

raceback (most recent call last):
  File "$MY_PROJECT/.direnv/python-3.11/lib/python3.11/site-packages/snowflake/snowpark/session.py", line 434, in getOrCreate
    session = _get_active_session()
              ^^^^^^^^^^^^^^^^^^^^^
  File "$MY_PROJECT/.direnv/python-3.11/lib/python3.11/site-packages/snowflake/snowpark/session.py", line 219, in _get_active_session
    raise SnowparkClientExceptionMessages.SERVER_NO_DEFAULT_SESSION()
snowflake.snowpark.exceptions.SnowparkSessionException: (1403): No default Session is found. Please create a session before you call function 'udf' or use decorator '@udf'.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "$MY_PROJECT/test.py", line 4, in <module>
    session = Session.builder.config("connection_name", "trial").getOrCreate()
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "$MY_PROJECT/.direnv/python-3.11/lib/python3.11/site-packages/snowflake/snowpark/session.py", line 441, in getOrCreate
    return self.create()
           ^^^^^^^^^^^^^
  File "$MY_PROJECT/.direnv/python-3.11/lib/python3.11/site-packages/snowflake/snowpark/session.py", line 419, in create
    session = self._create_internal(self._options.get("connection"))
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "$MY_PROJECT/.direnv/python-3.11/lib/python3.11/site-packages/snowflake/snowpark/session.py", line 461, in _create_internal
    ServerConnection({}, conn) if conn else ServerConnection(self._options),
                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "$MY_PROJECT/.direnv/python-3.11/lib/python3.11/site-packages/snowflake/snowpark/_internal/server_connection.py", line 159, in __init__
    self._conn = conn if conn else connect(**self._lower_case_parameters)
                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "$MY_PROJECT/.direnv/python-3.11/lib/python3.11/site-packages/snowflake/connector/__init__.py", line 55, in Connect
    return SnowflakeConnection(**kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "$MY_PROJECT/.direnv/python-3.11/lib/python3.11/site-packages/snowflake/connector/connection.py", line 456, in __init__
    self.connect(**kwargs)
  File "$MY_PROJECT/.direnv/python-3.11/lib/python3.11/site-packages/snowflake/connector/connection.py", line 771, in connect
    self.__open_connection()
  File "$MY_PROJECT/.direnv/python-3.11/lib/python3.11/site-packages/snowflake/connector/connection.py", line 1099, in __open_connection
    self.authenticate_with_retry(self.auth_class)
  File "$MY_PROJECT/.direnv/python-3.11/lib/python3.11/site-packages/snowflake/connector/connection.py", line 1386, in authenticate_with_retry
    self._authenticate(auth_instance)
  File "$MY_PROJECT/.direnv/python-3.11/lib/python3.11/site-packages/snowflake/connector/connection.py", line 1398, in _authenticate
    auth_instance.prepare(
  File "$MY_PROJECT/.direnv/python-3.11/lib/python3.11/site-packages/snowflake/connector/auth/keypair.py", line 132, in prepare
    raise TypeError(
TypeError: Expected bytes or RSAPrivateKey, got <class 'NoneType'>

How to reproduce

  1. Create a ~/.snowflake/config.toml with the following content
[connections]
[connections.trial]
account = "myaccount"
user = "my_user"
private_key_path = "my encrypted private key file"
authenticator = "SNOWFLAKE_JWT
  1. Set private key password in a environment variable PRIVATE_KEY_PAASSPHRASE

  2. Run snow connection test -c trial, it should be successful.

  3. Install pip install snowflake in your python venv,

  4. Now run the following python program

from snowflake.snowpark.session import Session
from snowflake.core import Root

session = Session.builder.config("connection_name", "trial").getOrCreate()
root = Root(session)

warehouses = root.warehouses
for w in warehouses.iter():
    print(w.name)

It should fail withe error TypeError: Expected bytes or RSAPrivateKey, got <class 'NoneType'>

  1. Now update the ~/.snowflake/config.toml as
[connections]
[connections.trial]
account = "myaccount"
user = "my_user"
private_key_file = "my encrypted private key file"
authenticator = "SNOWFLAKE_JWT
  1. Run the python test program again it should succeed.

Added support for private_key_file and kept private_key_path for backward compatibility, will be released in 3.0.0.