-
Notifications
You must be signed in to change notification settings - Fork 528
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
chore: add sshtunneler worker #19317
base: 3.6
Are you sure you want to change the base?
Conversation
e3d4300
to
88fe282
Compare
457ebe9
to
3878b49
Compare
a2541af
to
592009f
Compare
aeb1735
to
c7e60fd
Compare
8f529b1
to
f7fb948
Compare
@@ -45,3 +49,18 @@ func (f *Facade) RemoveSSHConnRequest(arg params.SSHConnRequestRemoveArg) (param | |||
} | |||
return params.ErrorResult{}, nil | |||
} | |||
|
|||
// ControllerAddresses returns the specified machine's public addresses. |
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.
a conceptual question: do we want machine agents to ssh to public addresses or private ones? idk which is guaranteed to be reachable from the unit
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.
That's a good question. Using ScopeMatchPublic
returns the public addresses as the first priority, then ScopeCloudLocal
then ScopeFanLocal, ScopeUnknown
. Arguably, ScopeCloudLocal
might make more sense if that can reduce latency between the controller and the units. I'll leave this comment unresolved for others to chime in.
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.
@wallyworld @hpidcock any thoughts on this?
internal/sshtunneler/tunneler.go
Outdated
@@ -253,7 +258,12 @@ func (tt *Tracker) wait(ctx context.Context, recv chan (net.Conn), privateKey go | |||
case conn := <-recv: | |||
// We now have ownership of the connection, so we should close it | |||
// if the SSH dial fails. | |||
sshClient, err := tt.dialer.Dial(conn, defaultUser, privateKey) | |||
// | |||
// Safely ignore the host key since we are connecting through an |
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.
Avoid asserting something you can't prove. We know the inbound connection came from the machine agent, not that the port the machine agent connected us to is the sshd
of that machine.
I suggest you change the InsertSSHConnRequest
facade method to return the expected host keys for the machine we are expecting to connect.
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, but i wouldn't cram it into the InsertSSHConnRequest method response. Better to have a separate method, no?
Then again, we control the machine agent and if somebody compromised it, we have bigger problems, right?
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.
There is one fundamental issue I see here, around how we get the unit's host key. We could have the unit send it to us when it establishes the reverse-tunnel. Then we establish the SSH session using the keys the unit gave us, but that seems pointless.
Normally a client would get a server's host key through some side channel but unless the controller already knows the host keys for machines, we would be relying on the machine telling us its host key right.
@@ -45,3 +49,18 @@ func (f *Facade) RemoveSSHConnRequest(arg params.SSHConnRequestRemoveArg) (param | |||
} | |||
return params.ErrorResult{}, nil | |||
} | |||
|
|||
// ControllerAddresses returns the specified machine's public addresses. |
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.
@wallyworld @hpidcock any thoughts on this?
internal/sshtunneler/tunneler.go
Outdated
@@ -253,7 +258,12 @@ func (tt *Tracker) wait(ctx context.Context, recv chan (net.Conn), privateKey go | |||
case conn := <-recv: | |||
// We now have ownership of the connection, so we should close it | |||
// if the SSH dial fails. | |||
sshClient, err := tt.dialer.Dial(conn, defaultUser, privateKey) | |||
// | |||
// Safely ignore the host key since we are connecting through an |
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, but i wouldn't cram it into the InsertSSHConnRequest method response. Better to have a separate method, no?
Then again, we control the machine agent and if somebody compromised it, we have bigger problems, right?
Create an tunnel tracker object within a sshtunneler worker.
When dialling the machine, we verify its host key by using the keys known to the Juju controller. To avoid ambiguity between the number of structs/methods that include the term host-key, I've renamed the sshserver controller facade methods and structs to explicitly mention the word "virtual". The client facade for `sshclient` has the same issues but I have not changed the naming of the facade there to avoid backwards compatability issues.
This PR builds on #19285, that PR should land first. It also requires the changes from #19301.
This PR builds on the
internal/sshtunneler
package and adds it into a worker so that a singleton object can be passed to dependents like thesshserver
worker who need to create SSH tunnels to machines.This PR has roughly 3 components,
internal/worker/sshtunneler
that aims to be very simple, providing dependency injection.sshtunneler
facade to supportControllerAddresses
andMachineHostKeys
methods to retrieve the controller machine's public addresses, and any machines public host keys, respectively. Additionally, some cleanup to this package.api/controller/sshtunneler
.Additionally some refactoring that was done along the way,
The client facade for
sshclient
has the same issues and while I've renamed the RPC structs, I have not changed the naming of the facade to avoid backwards compatibility issues.In a follow-up PR I will plug the tunneler worker into its dependants.
I suggest reviewing this PR commit-by-commit.
Checklist
QA steps
make install
juju bootstrap lxd test-tunneler --build-agent
Links
Jira card: JUJU-7549