SNOW-1752110: generate-jwt should not fail on empty passphrase
sfc-gh-vtimofeenko opened this issue · 6 comments
SnowCLI version
Snowflake CLI version: 3.2.0.dev0
Python version
Python 3.11.6
Platform
macOS-14.7-arm64-arm-64bit
What happened
For a key without passphrase, the passphrase is passed as empty string instead of None
.
Potential fixes
Use dynamic defaults for prompts
Move passphrase to arguments for generate_jwt
function and use this click approach allows automating the "don't show prompt if envvar is set".
Use value_proc in typer's prompt
Basically this will use a tiny value post-processor which turns empty string into None. Seems to work (all tests pass, jwt is generated); I'd be happy to submit a PR.
diff --git a/src/snowflake/cli/_plugins/connection/commands.py b/src/snowflake/cli/_plugins/connection/commands.py
index 543f70f2..0b34eec2 100644
--- a/src/snowflake/cli/_plugins/connection/commands.py
+++ b/src/snowflake/cli/_plugins/connection/commands.py
@@ -13,6 +13,7 @@
# limitations under the License.
from __future__ import annotations
+from typing import Optional
import logging
import os.path
@@ -386,12 +387,18 @@ def generate_jwt(
) -> CommandResult:
"""Generate a JWT token, which will be printed out and displayed.."""
passphrase = os.getenv("PRIVATE_KEY_PASSPHRASE", None)
+
+ def maybe_str(x: str) -> Optional[str]:
+ """Parser turns empty string into None."""
+ return None if x == "" else str(x)
+
if not passphrase:
passphrase = typer.prompt(
"Enter private key file password (Press enter if none)",
hide_input=True,
type=str,
default="",
+ value_proc=maybe_str,
)
try:
token = connector.auth.get_token_from_private_key(
Console output
❯ snow connection generate-jwt --private-key <path-to-p8>
Enter private key file password (Press enter if none) []: # Press enter here
An unexpected exception occurred. Use --debug option to see the traceback. Exception message:
Password was given but private key is not encrypted.
How to reproduce
- Set up a Snowflake user with key-pair auth, don't set the passphrase
- Try to generate jwt for the user
Interesting, I can't replicate the behavior. After this change I'm getting TypeError: Password was not given but private key is encrypted
on my key. While it works fine without your change. FYI the implementation is based on snowsql --generate-jwt
Looks like the latest version produces the same error without my patch:
❯ pipx install git+https://github.com/snowflakedb/snowflake-cli.git
⚠️ Note: snow was already on your PATH at /Users/vtimofeenko/.nix-profile/bin/snow
installed package snowflake-cli 3.2.0.dev0, installed using Python 3.11.9
These apps are now globally available
- snow
done! ✨ 🌟 ✨
❯ ~/.local/bin/snow --version
Snowflake CLI version: 3.2.0.dev0
❯ ~/.local/bin/snow --config-file=./test.toml connection generate-jwt
...config_manager.py:351: UserWarning: Bad owner or permissions on test.toml.
* To change owner, run `chown $USER "test.toml"`.
* To restrict permissions, run `chmod 0600 "test.toml"`.
warn(f"Bad owner or permissions on {str(filep)}{chmod_message}")
Enter private key file password (Press enter if none) []:
An unexpected exception occurred. Use --debug option to see the traceback. Exception message:
Password was given but private key is not encrypted.
❯ cat test.toml
[connections.default]
account = "<REDACTED>"
user = "snowcli_key_test"
private_key_path = "<REDACTED>"
If using RC4:
❯ pipx install git+https://github.com/snowflakedb/snowflake-cli.git@v3.1.0-rc4
⚠️ Note: snow was already on your PATH at /Users/vtimofeenko/.nix-profile/bin/snow
installed package snowflake-cli 3.1.0rc4, installed using Python 3.11.9
These apps are now globally available
- snow
done! ✨ 🌟 ✨
❯ ~/.local/bin/snow --version
Snowflake CLI version: 3.1.0rc4
❯ ~/.local/bin/snow --config-file=./test.toml connection generate-jwt
# <same complaint about permissions>
Enter private key file password (Press enter if none) []:
An unexpected exception occurred. Use --debug option to see the traceback. Exception message:
Password was given but private key is not encrypted.
Just tried this out in a (reasonably) clean environment, same thing.
The chevron ("❯") denotes the command I am executing in zsh. The line above it is the CWD.
~/.ssh
❯ openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out 1747.p8 -nocrypt
Generating RSA private key, 2048 bit long modulus
.......................+++++
.............+++++
e is 65537 (0x10001)
~/.ssh
❯ openssl rsa -in ./1747.p8 -pubout -out ./1747.pub
writing RSA key
❯ snow sql --query "CREATE USER REPR_1747 RSA_PUBLIC_KEY='$(cat ./1747.pub | grep -v '-' | tr -d '\n')'" # I usually use TYPE=SYSTEM, but let's not use it
CREATE USER REPR_1747 RSA_PUBLIC_KEY='MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx+MUeeI2PIXX1H+CAKBtvfy3y0y0zNhLGcqEkAheMDFEjFf5N2Tvtzufji/x2uPDawbRibsTi/WM1P8yEG+yxyibqXG4FYnGCOXtowR1G4n4VDEgjA6tz+xT/rqeQzOEt2X4562c1YMF7WbgAg/husDpS5t079/pBPp/EDS0uiOoJbjEzxK3yiHH6biZsFd0
KJJwE8etZKdzdjdvIIgwibA239mlpwi8lwBgheuepsPelWiSzjbFaiSBlpKzOhKI4fV4qCPGba5btzwQzONia/8siZ9Huaip1CTUuCSpAB0bcqKSP3HSpeb5ZBeRhMM0LDQa6fqpwhTs8eZm/QyydQIDAQAB'
+--------------------------------------+
| status |
|--------------------------------------|
| User REPR_1747 successfully created. |
+--------------------------------------+
~/.ssh
❯ cd $(mktemp -d)
# Just to make sure the env is pure
20zv3yk14bsdmy2f3qvvssgh0000gn/T/tmp.sZ7vPVD5xx
❯ cat <<EOF>config.toml
∙ [connections.default]
∙ EOF
# Install snowflake-cli using pipx and make sure pipx version is being used for reproducibility purposes
20zv3yk14bsdmy2f3qvvssgh0000gn/T/tmp.sZ7vPVD5xx
❯ pipx install snowflake-cli
⚠️ Note: snow was already on your PATH at /Users/vtimofeenko/.nix-profile/bin/snow
installed package snowflake-cli 3.1.0, installed using Python 3.11.9
These apps are now globally available
- snow
done! ✨ 🌟 ✨
20zv3yk14bsdmy2f3qvvssgh0000gn/T/tmp.sZ7vPVD5xx took 9s
❯ which snow
/Users/vtimofeenko/.nix-profile/bin/snow
20zv3yk14bsdmy2f3qvvssgh0000gn/T/tmp.sZ7vPVD5xx
❯ PATH=~/.local/bin:$PATH
20zv3yk14bsdmy2f3qvvssgh0000gn/T/tmp.sZ7vPVD5xx
❯ which snow
/Users/vtimofeenko/.local/bin/snow
20zv3yk14bsdmy2f3qvvssgh0000gn/T/tmp.sZ7vPVD5xx
❯ snow --version
Snowflake CLI version: 3.1.0
20zv3yk14bsdmy2f3qvvssgh0000gn/T/tmp.sZ7vPVD5xx
❯ chmod 600 ./config.toml
20zv3yk14bsdmy2f3qvvssgh0000gn/T/tmp.sZ7vPVD5xx
❯ snow --config-file ./config.toml connection list
+-------------------------------------------+
| connection_name | parameters | is_default |
|-----------------+------------+------------|
| default | {} | True |
+-------------------------------------------+
# Checking that env is empty:
20zv3yk14bsdmy2f3qvvssgh0000gn/T/tmp.sZ7vPVD5xx took 28s
❯ env | rg SNOWFLAKE
# It is empty, no SNOWFLAKE vars
# OK, we have snowcli freshly installed, there is nothing in the config file
# Let's try generate-jwt with just command-line supplied args
❯ snow --config-file ./config.toml connection generate-jwt --private-key-path ~/.ssh/1747.p8 --account "<REDACTED>" --user "REPR_1747"
Enter private key file password (Press enter if none) []: # << just hit "Enter"
An unexpected exception occurred. Use --debug option to see the traceback. Exception message:
Password was given but private key is not encrypted.
# Just in case my environment is messing with things, let's try bash:
❯ bash
# ...
bash-3.2$ snow --config-file ./config.toml connection generate-jwt --private-key-path ~/.ssh/1747.p8 --account "<REDACTED>" --user "REPR_1747"
Enter private key file password (Press enter if none) []:
An unexpected exception occurred. Use --debug option to see the traceback. Exception message:
Password was given but private key is not encrypted.
# Let's try the live version back in zsh
20zv3yk14bsdmy2f3qvvssgh0000gn/T/tmp.sZ7vPVD5xx
❯ pipx install git+https://github.com/snowflakedb/snowflake-cli.git
⚠️ Note: snow was already on your PATH at /Users/vtimofeenko/.nix-profile/bin/snow
installed package snowflake-cli 3.2.0.dev0, installed using Python 3.11.9
These apps are now globally available
- snow
done! ✨ 🌟 ✨
20zv3yk14bsdmy2f3qvvssgh0000gn/T/tmp.sZ7vPVD5xx took 16s
❯ which snow
/Users/vtimofeenko/.local/bin/snow
20zv3yk14bsdmy2f3qvvssgh0000gn/T/tmp.sZ7vPVD5xx
❯ snow --version
Snowflake CLI version: 3.2.0.dev0
20zv3yk14bsdmy2f3qvvssgh0000gn/T/tmp.sZ7vPVD5xx took 3s
❯ snow --config-file ./config.toml connection generate-jwt --private-key-path ~/.ssh/1747.p8 --account "<REDACTED>" --user "REPR_1747"
Enter private key file password (Press enter if none) []:
An unexpected exception occurred. Use --debug option to see the traceback. Exception message:
Password was given but private key is not encrypted.
# Same thing :(
Thanks! The problem is caused by -nocrypt
. It seems that using -nocrypt
causes to the key to have really no passphrase as opposed to clicking enter on passphrase promt.
@sfc-gh-vtimofeenko would you mind testing out #1841 locally? I was able to replicate both cases (no passphrase and empty passphrase) and the code should work now for both cases.
Thank you very much!
Works fine:
❯ pipx install git+https://github.com/snowflakedb/snowflake-cli.git
❯ PATH=~/.local/bin:$PATH
❯ snow --config-file ./config.toml connection generate-jwt --private-key-path ~/.ssh/1747.p8 --account "<REDACTED>" --user "REPR_1747"
<proper JWT>