From 9bbc1d41d0a9cf8d4605a552e3fceb25c7dc4341 Mon Sep 17 00:00:00 2001 From: Jose Castro Leon Date: Tue, 4 Dec 2018 15:43:26 +0100 Subject: [PATCH] Adds private_key parameter in the standard ssh actions This method allows to specify a private key and avoids its storage in the filesystem of the executors. This can be used later in combination of a secrets_retrieve to use keys stored in barbican. Change-Id: Ide438a7f6d24c8bdc9eb2c82e935fd39a6acc2c6 Closes-Bug: #1806703 --- mistral/actions/std_actions.py | 12 +++++--- .../tests/unit/actions/test_std_ssh_action.py | 3 +- mistral/utils/ssh_utils.py | 30 ++++++++++++++----- .../std-ssh-add-pkey-2c665a81ff9fbdfd.yaml | 6 ++++ 4 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 releasenotes/notes/std-ssh-add-pkey-2c665a81ff9fbdfd.yaml diff --git a/mistral/actions/std_actions.py b/mistral/actions/std_actions.py index 2b1706722..794b04418 100644 --- a/mistral/actions/std_actions.py +++ b/mistral/actions/std_actions.py @@ -376,7 +376,7 @@ class SSHAction(actions.Action): return ssh_utils.execute_command def __init__(self, cmd, host, username, - password="", private_key_filename=None): + password="", private_key_filename=None, private_key=None): super(SSHAction, self).__init__() self.cmd = cmd @@ -384,13 +384,15 @@ class SSHAction(actions.Action): self.username = username self.password = password self.private_key_filename = private_key_filename + self.private_key = private_key self.params = { 'cmd': self.cmd, 'host': self.host, 'username': self.username, 'password': self.password, - 'private_key_filename': self.private_key_filename + 'private_key_filename': self.private_key_filename, + 'private_key': self.private_key } def run(self, context): @@ -438,13 +440,15 @@ class SSHProxiedAction(SSHAction): def __init__(self, cmd, host, username, private_key_filename, gateway_host, gateway_username=None, - password=None, proxy_command=None): + password=None, proxy_command=None, + private_key=None): super(SSHProxiedAction, self).__init__( cmd, host, username, password, - private_key_filename + private_key_filename, + private_key ) self.gateway_host = gateway_host diff --git a/mistral/tests/unit/actions/test_std_ssh_action.py b/mistral/tests/unit/actions/test_std_ssh_action.py index 3d0017255..900a3ab4b 100644 --- a/mistral/tests/unit/actions/test_std_ssh_action.py +++ b/mistral/tests/unit/actions/test_std_ssh_action.py @@ -58,7 +58,8 @@ class SSHActionTest(base.BaseTest): host=host, username=username, password='', - private_key_filename=None + private_key_filename=None, + private_key=None ) @mock.patch.object(mistral.utils.ssh_utils, 'execute_command') diff --git a/mistral/utils/ssh_utils.py b/mistral/utils/ssh_utils.py index 4d135a625..8274a9a0a 100644 --- a/mistral/utils/ssh_utils.py +++ b/mistral/utils/ssh_utils.py @@ -37,13 +37,20 @@ def _read_paramimko_stream(recv_func): return result.decode('utf-8') -def _to_paramiko_private_key(private_key_filename, password=None): +def _to_paramiko_private_key(private_key_filename, + private_key=None, + password=None): if '../' in private_key_filename or '..\\' in private_key_filename: raise exc.DataAccessException( "Private key filename must not contain '..'. " "Actual: %s" % private_key_filename ) + if private_key: + return paramiko.RSAKey.from_private_key( + file_obj=six.StringIO(private_key), + password=password) + if private_key_filename.startswith('/'): private_key_path = private_key_filename else: @@ -56,9 +63,6 @@ def _to_paramiko_private_key(private_key_filename, password=None): def _connect(host, username, password=None, pkey=None, proxy=None): - if isinstance(pkey, six.string_types): - pkey = _to_paramiko_private_key(pkey, password) - LOG.debug('Creating SSH connection to %s', host) ssh_client = paramiko.SSHClient() @@ -104,10 +108,13 @@ def _execute_command(ssh_client, cmd, get_stderr=False, def execute_command_via_gateway(cmd, host, username, private_key_filename, gateway_host, gateway_username=None, - proxy_command=None, password=None): + proxy_command=None, password=None, + private_key=None): LOG.debug('Creating SSH connection') - private_key = _to_paramiko_private_key(private_key_filename, password) + private_key = _to_paramiko_private_key(private_key_filename, + private_key, + password) proxy = None @@ -153,9 +160,16 @@ def execute_command_via_gateway(cmd, host, username, private_key_filename, def execute_command(cmd, host, username, password=None, - private_key_filename=None, get_stderr=False, + private_key_filename=None, + private_key=None, get_stderr=False, raise_when_error=True): - ssh_client = _connect(host, username, password, private_key_filename) + LOG.debug('Creating SSH connection') + + private_key = _to_paramiko_private_key(private_key_filename, + private_key, + password) + + ssh_client = _connect(host, username, password, private_key) LOG.debug("Executing command %s", cmd) diff --git a/releasenotes/notes/std-ssh-add-pkey-2c665a81ff9fbdfd.yaml b/releasenotes/notes/std-ssh-add-pkey-2c665a81ff9fbdfd.yaml new file mode 100644 index 000000000..990e173a6 --- /dev/null +++ b/releasenotes/notes/std-ssh-add-pkey-2c665a81ff9fbdfd.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Adds the parameter private_key in the standard ssh actions. This allows a + user to specify the key to use instead of using the ones available in the + filesystem of the executors.