Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
add proper handling for golang ssh #1136
add proper handling for golang ssh #1136
Changes from all commits
2b55d99
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Throughout, in several instances of these changes: Why does it make sense to set a “host” field to something URI-like?
IMHO fields/variables, should almost always clear and unambiguous semantics — the obvious semantics. If there are two possible formats, have two separate variables/fields.
It would at least be somewhat manageable if the
ConnectionExecOptions.Host
field were clearly documented that way, but… it isn’t. How is someone in the future (3 years into the future? or maybe just next week) going to update this undocumented code, without exhaustively enumerating every single caller to understand what formats are acceptable? Or perhaps even validating many past versions of Podman to see what they were writing into persistent config files?If you currently know these things, please write them down.
If the user’s input is always supposed to be a host name and not an URI, but
Validate
uses an URI parser for some reason, I’d expectValidate
to do this internally (or, maybe, not to use an URI parser at all).If the user’s input can either be a URI or a non-URI, do we have to have that ambiguity? Maybe that ambiguity should only exist at some top CLI level (possibly as a helper provided by this package) but not here inside the fairly low levels of the API?
If the user’s input can be a URI, what happens if the input uses a different scheme than
ssh
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don’t understand what this comment is trying to say.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean, this is an improvement over the status quo but I’ve been talking about the need to interactively get user’s approval first, for some time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok I will prompt
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mtrmac this will actually break the machine tests since there is no way to force through the prompt. suggestions?
and most podman-remote tests actually
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For machine, maybe that’s consistent with the
isMachine
bool in general. But that rather depends on the specifics of the semantics of that field.For “most podman-remote tests”, how does that fail? (It might very well be possible but just a lot of work.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how would a simple command to a new "machine" in the e2e tests work in the testing suite if we need to prompt for y/n to continue?
I could do a timeout default yes here, where if the user starts a machine or executes podman-remote and doesn't answer y/n we default to yes after 15 seconds.
Other than that, this is a huge hindrance to regular usage and people who use this in applied scenarios... a very breaking change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whatever the current equivalent of
expect(1)
is. I assume (without checking) that we have some tests ofpodman run -it
, that’s the same issue.No thank you. That’s not an explicit expression of intent.
How is prompting on
podman connection add
, and never again, a huge hindrance?I’ve been talking about the need to interactively prompt since the very start of the existence of this package, and bringing up the need to walk though the UX to ensure it is practical.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree a prompt is best but that is not something that can be introduced in 4.3 I do not think. if you exec
podman-remote
or any podman machine command and it idles, we will break a lot of existing builds.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this code is confident enough to in the public key to add an entry, why would it be reluctant to create a new file with a single line?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought our desired path was to warn people for a few podman versions and then maybe talk about creating a file? I think this is exiting the scope of this PR.
This fix is needed for 4.3 next week
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @mtrmac. The stock behavior for podman machine is that a file does not need to be created. Granted, it was because it wasn't in use, but from a UX perspective, we should avoid having podman machine instances break after the upgrade. This is also the stock behavior for stock ssh (silent file creation). Change-wise should be safe and small (just adding O_CREATE to flags)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@n1hility This path is not really a
podman machine
concern in this sense. If the file is entirely missing, we get into the other path with theinsecureIsMachineConnection
check.Even this path does not break machines, it warns and continues.
It’s the non-machine case where the behavior between existing file with no match / no file is hard for me to understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, my original comment is way off base.
If we get to the path that start with a
known()
call at all, we know that the file did exist when creatingknown
. So the only way we can get here is if someone removedknown_hosts
, or a parent directory, between the read and this write.In that case I don’t think we really need any special handling for
os.IsNotExist
(though usingO_CREATE
would, I think, be closer to the right thing to do [with the absolutely right thing being worrying about locking theknown_hosts
writers across disparate implementations??? ugh]).But also, the current warning text seems very unrelated to the situation at hand: it is warning about a
known_hosts
file that did exist just a few milliseconds ago.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mtrmac @cdoern aha sorry! I just skimmed the shown snippets without looking at the full code. Ok, that alleviates my primary concern.
That said I agree it would make sense to auto-create in the non-machine case as well, and this could simplify the logic a bit.
I think its ok relying on O_APPENDs atomicity as long as its always one write for the record. I just double checked the openssh source and they dont use cooperative file locking on known hosts, so its effect would be limited to just concurrent usage of podman
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am mocking up a version where we create a known_hosts file which removes the need for
insecureIsMachineConnection
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for taking the time to actually check. Yes, looking at
add_host_to_hostfile
in https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/hostfile.c?rev=1.93&content-type=text/x-cvsweb-markup , we don’t need to do any better than that:\n
, don’t worry about files that don’t end with a newline.~/.ssh
, and in that case it is fairly important to use mode 0700).I guess that’s for a future version?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mtrmac do you think we should merge this as is for 4.3? I modified it locally to create ~/.ssh/known_hosts, I can push that if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cdoern I apologize, for some reason I thought that our 4.2 baseline is #1094 , and that this PR is a net decrease in security. I have only today actually checked, and 4.2 has the pre-c/common ssh implementation if I’m not mistaken.
Assuming that’s the case, any version of this is an improvement over 4.2. So, at this point I think the priorities are, in this order:
ssh_native
and theIsMachineConnection
cases?)And for 4.4, let’s first document what we want to do, then see what pieces are missing, and finally finish this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Non-blocking: Simplifying this to
default: return hErr
would make it a tiny bit clearer that we never returnnil
without being intentional about it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely non-blocking: The caller already computed this, so it could pass a path instead of this function recomputing.
(Right now this makes ~no difference, but it will eventually help if we start maintaining per-machine known_hosts files in non-default locations.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Non-blocking, about all of
Validate
:This kind of parsing/transformation function, overall, seems to me like a pretty good candidate for writing fairly exhaustive unit tests: it is
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Non-blocking: BTW naming a transformative parser like this “validate” is a bit misleading.
Non-blocking: And why are native callers passing
options.Identity
to this function, and immediately afterwards toValidateAndConfigure
? It seems to me that this could be simplified, e.g. by this function returning a struct (resolvedConnectionInfo
[1]?), and callers can then pass around that single struct and accessdest.URI
anddest.Identity
.[1] I guess that struct can’t be
*config.Destination
, because the on-disk format and the normalized internal data seem to differ.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Regardless of the name, AFAICS
Validate
does not need to be public at all; so, with the recent plans to make the c/common API stable, it should start private. We can easily make things public later, but we can’t take back public API nearly as easily. This applies to other functions in this package as well.)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this supposed to do? Consider things like
ssh://run.my.machines
.Contains
condition? My best guess (which is a bad guess, there is no documentation) is thatsock
is supposed to be set to something likeuri.Path
; if there is some special reason not to use exactly that, it is not documented.Applies similarly to various other instances of
"/run"
in this subpackage.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See elsewhere, why do the callers need to deal with that?
Why is a “path” parameter being parsed as an URI? What is the actually intended semantics of that value? Please name parameters exactly correctly, or if that’s impossible (preferably restructure code to make that possible, or at least) clearly, and exhaustively, document the expected formats, in the function’s/field’s doc string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the “sometimes we are not going to have a path” comment below?
ssh://foo
andssh://user@foo
, but that didn’t match the code. If there is a a corner case (ssh:foo
??), it should be documented clearly — perhaps in a comment, but ideally actually documented also by a unit test that ensures the behavior is not accidentally broken.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if both
uri.Port()
andport
is set?Looking at various Podman callers, so many (but not all of them) call
url.Parse
themselves already. Why do that twice, and then need to worry about these port/port conflicts that might not be actually possible in practice?Maybe there should be a single
ssh.Destination
type, containing all relevant information in a native support optimized for further use (whether that’s anurl.URL
, individual values, or some combination), and helpers vaguely likeDestinationFromConfigDestination(*config.Destination)
,DestinationFromURI
,DestinationFromCLIString
,DestinationFromPodmanConnectionAddComponents
— each with appropriate heuristics, without several round-trips back and forth.