-
-
Notifications
You must be signed in to change notification settings - Fork 751
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
Rough SSH Bastion Host Support (relates to #2144) #2150
Conversation
transport = self.bastion_client.get_transport() | ||
real_addr = (self.hostname, self.port) | ||
# no attempt is made to bind local_addr, so something very "wrong" is used | ||
local_addr = ('256.256.256.256', 65536) |
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 wasn't 100% sure on what values to use here. Originally I had 127.0.0.1:1234, but since it doesn't actually bind the socket, I thought it made sense to use something that was completely outside of spec.
I am taking a look at this PR but we should wait for @lakshmi-kannan and @Kami. |
@@ -216,6 +218,12 @@ def _execute_in_pool(self, execute_method, **kwargs): | |||
return results | |||
|
|||
def _connect(self, host, results, raise_on_any_error=False): | |||
bastion_hostname, bastion_port = None, None | |||
|
|||
if "!" in host: |
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.
Typically breaking out magic string as a constant helps.
Probably place it somewhere https://github.com/StackStorm/st2/blob/master/st2common/st2common/constants/runners.py
968b7ac
to
cec5dbe
Compare
The is the most python I've written, ever.
cec5dbe
to
84d3268
Compare
local_addr = ('256.256.256.256', 65536) | ||
channel = transport.open_channel("direct-tcpip", real_addr, local_addr) | ||
|
||
conninfo = {'hostname': '256.256.256.256', |
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.
can use local_addr[0] and local_addr[1]
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 makes sense from a logging perspective.
This made me realize the AutoAddPolicy
the ParamikoSSH client uses will end up erroring if you have two hosts with the same IP behind the bastion host- I'll change the policy to WarningPolicy
.
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.
Update: nevermind, it appears as though it's not saved on disk as no host_keys_file is specified on the clients.
High level this is great. most of my comments are really cosmetic things. Few thoughts -
|
Also, perhaps a good idea to add some units - https://github.com/StackStorm/st2/blob/master/st2actions/tests/unit/test_parallel_ssh.py |
I was thinking about a bastion_host property, but my understanding is that it would require the modification of any actions using it to add the bastion_host(s) parameter. I would like to make it explicit, but that's a large drawback. If there is a way to implicitly add the bastion_host(s) parameter to all actions supporting the |
Actually if we make bastion_host(s) an optional runner_parameter then all actions get it for free. Concretely adding another property like -
This is a tricky one. Unless we come up with a To run against multiple groups would require multiple executions. If practically it turns out to be the common case then we can look at options as the next step. |
@manasdk much cleaner this way, just need to figure out unit tests |
@@ -111,6 +111,11 @@ def __init__(self, hostname, port=22, username=None, password=None, | |||
self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) | |||
self.logger = logging.getLogger(__name__) | |||
self.sftp = None | |||
self.bastion_host = bastion_host |
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.
self._bastion_host. Can you also use the _ convention everywhere consistently?
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 didn't use _bastion_host
as the other properties on ParamikoSSHClient
aren't prefixed.
The SSH connection is established when connect is called this requires mocking SSHClient for those methods
local_addr = ('', 0) | ||
self.bastion_socket = transport.open_channel('direct-tcpip', real_addr, local_addr) | ||
|
||
self.client = self._connect(self.hostname, self.bastion_socket) |
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.
self._connect(host=self.hostname, socket=self.bastion_socket) would be better.
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'll do the same on line 127 as well.
self.bastion_client = self._connect(self.bastion_host) | ||
transport = self.bastion_client.get_transport() | ||
real_addr = (self.hostname, self.port) | ||
local_addr = ('', 0) |
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 it's not too much hassle, could you please include the link to the fabric commit as a link? This might throw off other people when they read the code. Some helpful hinting would be nice IMO.
It's looking much better now in terms of code and tests.
One other thing I thought was if bastion host had a non standard SSH port, we'll need to add ability to handle that. But we'll make the person requiring the feature to add that ;). Thanks for being patient. We'll merge this soon! |
@lakshmi-kannan something something security something obscurity :) |
LGTM. Merging now. |
Rough SSH Bastion Host Support (relates to #2144)
@lakshmi-kannan or @lattwood I has started using stack storm recently. My environment is accessed by only one jump box. My stack storm is installed on a new box where i have passwordless connectivity to jump server. i have to use my jump server as bastion host and then trigger my scripts on target hosts. can you please post me some examples how to use or configure the bastion host details in stackstorm. i desperately need your help. |
ParamikoSSHBastionClient
as a subclass ofParamikoSSHClient
, with overriddenconnect
andclose
methods for connection bouncing.ParamikoSSHBastionClient
if a!
exists in the host. The left side of the!
is the bastion host, right side is the target host.Rudimentary testing was done with https://gist.github.com/lattwood/4c52ba7b8583ae4565eb, I'll be doing more extensive testing using
st2workroom
today. This touches on #2144This is the most python I've written so I apologize in advance if anything isn't done the python way.
Is a CLA required or would Apache licensing suffice?