Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: make dvc-ssh compatible with asyncssh>=2.19.0 #100

Merged
merged 1 commit into from
Feb 5, 2025
Merged

Conversation

skshetry
Copy link
Member

@skshetry skshetry commented Feb 3, 2025

No description provided.


# We are going to automatically add stuff to known_hosts
# something like paramiko's AutoAddPolicy()
login_info["known_hosts"] = None
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines -85 to -88
if config.get("keyfile"):
raw_keys.append(config.get("keyfile"))
elif user_ssh_config.get("IdentityFile"):
raw_keys.extend(user_ssh_config.get("IdentityFile"))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If client_keys is specified, it does not use IdentityFile, nor does it try to load keys from default paths.

Same thing happens with IdentityFile, it does not load other keys from default paths.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so, you are saying it's fine for us to change / drop the existing logic and don't try to use all the keys? (just to clarify)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so, you are saying it's fine for us to change / drop the existing logic and don't try to use all the keys? (just to clarify)

I am only stating what is happening. In the diff, you can see that either client_keys can be a keyfile that is set in config or falls back to use IdentityFile user's ssh config. We don't use all the keys, it's either-or.

raw_keys = []
if config.get("keyfile"):
raw_keys.append(config.get("keyfile"))
elif user_ssh_config.get("IdentityFile"):
raw_keys.extend(user_ssh_config.get("IdentityFile"))

asyncssh already does the latter automatically if no client_keys gets passed.
So, we don't need to do that.

Regarding "not using all keys," I believe this behavior is generally preferred since it avoids the need to test every key. This aligns with asyncssh's approach, where a default set of key file paths is used if client_keys or IdentityFile is not specified. However, if either is set, only the specified keys are used, and the default keys are ignored.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, okay ... that's right. It makes the migration simpler.

@@ -108,11 +87,6 @@ def _prepare_credentials(self, **config):

login_info["gss_auth"] = config.get("gss_auth", False)
login_info["agent_forwarding"] = config.get("agent_forwarding", True)
login_info["proxy_command"] = user_ssh_config.get("ProxyCommand")
Copy link
Member Author

@skshetry skshetry Feb 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have a config for this in dvc. ProxyCommand is supported in asyncssh from openssh config AFAIK.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, that was a weird one

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this was copied straight from paramiko based filesystem.
I see that asyncssh got proxy_command support as well as OpenSSH's ProxyCommand support at the same time: ronf/asyncssh#376 (commit ronf/asyncssh@47375c4).

Comment on lines 58 to 64
for option in ("password", "passphrase"):
login_info[option] = config.get(option)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we don't really need ask_* options, as we have support for keyboard-interactive authentication support. See #12.

But this is not a big issue either. It would be nice to also support password authentication interactively, but that's a nice to have.

@skshetry skshetry marked this pull request as ready for review February 4, 2025 08:04
Comment on lines +16 to +23
prompt = f"Enter a {desc} for"
if user:
prompt += f" {user}@{host}"
else:
prompt += f" {host}"
if port:
prompt += f":{port}"
prompt += ":\n"
Copy link
Member Author

@skshetry skshetry Feb 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to make these conditional, since we don't use the defaults anymore.

These will likely get removed when we start using a proper callback (will do in next PR).

Comment on lines +74 to +75
if keyfile := config.get("keyfile"):
login_info["client_keys"] = [os.path.expanduser(keyfile)]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing worth mentioning, if keyfile is set and passphrase/ask_passphrase is not set, DVC fails without asking for a passphrase. This is working as expected, but we do prompt for passphrase for default keyfiles or the one specified in the user's config. So, we are diverging a bit.

asyncssh can take a passphrase callable, so if we pass it, it will also get called for these client_keys. This will unify the behavior and remove the need for eager ask_passphrase callback above.

Will create a PR for this separately.

Copy link
Member Author

@skshetry skshetry Feb 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nvmd, ignore that. passphrase callable will be called for every key, even unencrpyted ones.

@skshetry skshetry merged commit e452803 into main Feb 5, 2025
16 checks passed
@skshetry skshetry deleted the fix-54 branch February 5, 2025 02:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants