[ https://issues.apache.org/jira/browse/AIRFLOW-3410?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16702139#comment-16702139 ]
ASF GitHub Bot commented on AIRFLOW-3410: ----------------------------------------- kaxil closed pull request #4249: [AIRFLOW-3410] Add feature to allow Host Key Change for SSH Op URL: https://github.com/apache/incubator-airflow/pull/4249 This is a PR merged from a forked repository. As GitHub hides the original diff on merge, it is displayed below for the sake of provenance: As this is a foreign pull request (from a fork), the diff is supplied below (as it won't show otherwise due to GitHub magic): diff --git a/airflow/contrib/hooks/ssh_hook.py b/airflow/contrib/hooks/ssh_hook.py index c496762187..97e93bbc60 100755 --- a/airflow/contrib/hooks/ssh_hook.py +++ b/airflow/contrib/hooks/ssh_hook.py @@ -80,6 +80,7 @@ def __init__(self, # Default values, overridable from Connection self.compress = True self.no_host_key_check = True + self.allow_host_key_change = False self.host_proxy = None # Placeholder for deprecated __enter__ @@ -110,6 +111,10 @@ def __init__(self, and\ str(extra_options["no_host_key_check"]).lower() == 'false': self.no_host_key_check = False + if "allow_host_key_change" in extra_options\ + and\ + str(extra_options["allow_host_key_change"]).lower() == 'true': + self.allow_host_key_change = True if not self.remote_host: raise AirflowException("Missing required param: remote_host") @@ -146,8 +151,13 @@ def get_conn(self): self.log.debug('Creating SSH client for conn_id: %s', self.ssh_conn_id) client = paramiko.SSHClient() - client.load_system_host_keys() + if not self.allow_host_key_change: + self.log.warning('Remote Identification Change is not verified. ' + 'This wont protect against Man-In-The-Middle attacks') + client.load_system_host_keys() if self.no_host_key_check: + self.log.warning('No Host Key Verification. This wont protect ' + 'against Man-In-The-Middle attacks') # Default is RejectPolicy client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) diff --git a/airflow/www/static/connection_form.js b/airflow/www/static/connection_form.js index 5a74813d5b..8ed42c2dbe 100644 --- a/airflow/www/static/connection_form.js +++ b/airflow/www/static/connection_form.js @@ -61,6 +61,12 @@ 'password': 'Auth Token', } }, + ssh: { + hidden_fields: ['schema'], + relabeling: { + 'login': 'Username', + } + }, } function connTypeChange(connectionType) { $("div.form-group").removeClass("hide"); diff --git a/airflow/www_rbac/static/js/connection_form.js b/airflow/www_rbac/static/js/connection_form.js index dabd1f7359..09034f8785 100644 --- a/airflow/www_rbac/static/js/connection_form.js +++ b/airflow/www_rbac/static/js/connection_form.js @@ -53,6 +53,12 @@ $(document).ready(function () { 'password': 'Auth Token', } }, + ssh: { + hidden_fields: ['schema'], + relabeling: { + 'login': 'Username', + } + }, }; function connTypeChange(connectionType) { diff --git a/docs/howto/manage-connections.rst b/docs/howto/manage-connections.rst index ec5cce189c..35b5807c9e 100644 --- a/docs/howto/manage-connections.rst +++ b/docs/howto/manage-connections.rst @@ -216,7 +216,7 @@ Extra (optional) } When specifying the connection as URI (in AIRFLOW_CONN_* variable) you should specify it - following the standard syntax of DB connections, where extras as passed as parameters + following the standard syntax of DB connections, where extras are passed as parameters of the URI (note that all components of the URI should be URL-encoded). For example: @@ -248,7 +248,7 @@ Password (required) Specify the password to connect. Extra (optional) - Specify the extra parameters (as json dictionary) that can be used in mysql + Specify the extra parameters (as json dictionary) that can be used in postgres connection. The following parameters out of the standard python parameters are supported: @@ -278,12 +278,12 @@ Extra (optional) { "sslmode": "verify-ca", "sslcert": "/tmp/client-cert.pem", - "sslca": "/tmp/server-ca.pem'", + "sslca": "/tmp/server-ca.pem", "sslkey": "/tmp/client-key.pem" } When specifying the connection as URI (in AIRFLOW_CONN_* variable) you should specify it - following the standard syntax of DB connections, where extras as passed as parameters + following the standard syntax of DB connections, where extras are passed as parameters of the URI (note that all components of the URI should be URL-encoded). For example: @@ -321,7 +321,7 @@ Password (required) Specify the password to connect. Extra (optional) - Specify the extra parameters (as json dictionary) that can be used in mysql + Specify the extra parameters (as json dictionary) that can be used in gcpcloudsql connection. Details of all the parameters supported in extra field can be found in @@ -341,7 +341,7 @@ Extra (optional) } When specifying the connection as URI (in AIRFLOW_CONN_* variable) you should specify it - following the standard syntax of DB connections, where extras as passed as parameters + following the standard syntax of DB connections, where extras are passed as parameters of the URI (note that all components of the URI should be URL-encoded). For example: @@ -350,3 +350,51 @@ Extra (optional) gcpcloudsql://user:XXXXXXXXX@1.1.1.1:3306/mydb?database_type=mysql&project_id=example-project&location=europe-west1&instance=testinstance&use_proxy=True&sql_proxy_use_tcp=False +SSH +~~~ +The SSH connection type provides connection to use :class:`~airflow.contrib.hooks.ssh_hook.SSHHook` to run commands on a remote server using :class:`~airflow.contrib.operators.ssh_operator.SSHOperator` or transfer file from/to the remote server using :class:`~airflow.contrib.operators.ssh_operator.SFTPOperator`. + +Configuring the Connection +'''''''''''''''''''''''''' +Host (required) + The Remote host to connect. + +Username (optional) + The Username to connect to the remote_host. + +Password (optional) + Specify the password of the username to connect to the remote_host. + +Port (optional) + Port of remote host to connect. Default is 22. + +Extra (optional) + Specify the extra parameters (as json dictionary) that can be used in ssh + connection. The following parameters out of the standard python parameters + are supported: + + * **timeout** - An optional timeout (in seconds) for the TCP connect. Default is ``10``. + * **compress** - ``true`` to ask the remote client/server to compress traffic; `false` to refuse compression. Default is ``true``. + * **no_host_key_check** - Set to ``false`` to restrict connecting to hosts with no entries in ``~/.ssh/known_hosts`` (Hosts file). This provides maximum protection against trojan horse attacks, but can be troublesome when the ``/etc/ssh/ssh_known_hosts`` file is poorly maintained or connections to new hosts are frequently made. This option forces the user to manually add all new hosts. Default is ``true``, ssh will automatically add new host keys to the user known hosts files. + * **allow_host_key_change** - Set to ``true`` if you want to allow connecting to hosts that has host key changed or when you get 'REMOTE HOST IDENTIFICATION HAS CHANGED' error. This wont protect against Man-In-The-Middle attacks. Other possible solution is to remove the host entry from ``~/.ssh/known_hosts`` file. Default is ``false``. + + Example "extras" field: + + .. code-block:: json + + { + "timeout": "10", + "compress": "false", + "no_host_key_check": "false", + "allow_host_key_change": "false" + } + + When specifying the connection as URI (in AIRFLOW_CONN_* variable) you should specify it + following the standard syntax of connections, where extras are passed as parameters + of the URI (note that all components of the URI should be URL-encoded). + + For example: + + .. code-block:: bash + + ssh://user:pass@localhost:22?timeout=10&compress=false&no_host_key_check=false&allow_host_key_change=true diff --git a/tests/contrib/hooks/test_ssh_hook.py b/tests/contrib/hooks/test_ssh_hook.py index ad5621fe92..64b015d09e 100644 --- a/tests/contrib/hooks/test_ssh_hook.py +++ b/tests/contrib/hooks/test_ssh_hook.py @@ -132,15 +132,18 @@ def test_tunnel_without_password(self, ssh_mock): def test_conn_with_extra_parameters(self): db.merge_conn( - models.Connection(conn_id='ssh_with_extra', - host='localhost', - conn_type='ssh', - extra='{"compress" : true, "no_host_key_check" : "true"}' - ) + models.Connection( + conn_id='ssh_with_extra', + host='localhost', + conn_type='ssh', + extra='{"compress" : true, "no_host_key_check" : "true", ' + '"allow_host_key_change": false}' + ) ) ssh_hook = SSHHook(ssh_conn_id='ssh_with_extra') self.assertEqual(ssh_hook.compress, True) self.assertEqual(ssh_hook.no_host_key_check, True) + self.assertEqual(ssh_hook.allow_host_key_change, False) def test_ssh_connection(self): hook = SSHHook(ssh_conn_id='ssh_default') ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org > Remote Host Identification Has Changed Error while using SSHOperator > -------------------------------------------------------------------- > > Key: AIRFLOW-3410 > URL: https://issues.apache.org/jira/browse/AIRFLOW-3410 > Project: Apache Airflow > Issue Type: New Feature > Components: contrib > Reporter: Kaxil Naik > Assignee: Kaxil Naik > Priority: Minor > Fix For: 1.10.2 > > > Currently, there is no provision in Airflow's implementation of SSHOperator > to disable Host Checking and use a Null Known Host file to allow connecting > to host that has a new IP. -- This message was sent by Atlassian JIRA (v7.6.3#76005)