Repository: ansible/ansible

Issue:
known_hosts module fails to set values with spurious error message
##### SUMMARY
The `known_hosts` module, when run in its default mode of adding entries to a file, fails with the error message "Host parameter does not match hashed host field in supplied key". This is not due to a problem with the key itself but rather in the way that the module writes the test file.

##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
known_hosts

##### ANSIBLE VERSION
```
ansible 2.6.1
  config file = /home/ghelling/.ansible.cfg
  configured module search path = [u'/home/ghelling/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/ghelling/venv/tools/lib/python2.7/site-packages/ansible
  executable location = /home/ghelling/venv/tools/bin/ansible
  python version = 2.7.15 (default, May 16 2018, 17:50:09) [GCC 8.1.1 20180502 (Red Hat 8.1.1-1)]
```

##### CONFIGURATION
ANSIBLE_PIPELINING(/home/ghelling/.ansible.cfg) = True
ANSIBLE_SSH_ARGS(/home/ghelling/.ansible.cfg) = -o ControlMaster=auto -o ControlPersist=600s -o Identiti>
ANSIBLE_SSH_CONTROL_PATH(/home/ghelling/.ansible.cfg) = %(directory)s/%%h-%%r
ANSIBLE_SSH_CONTROL_PATH_DIR(/home/ghelling/.ansible.cfg) = /tmp
DEFAULT_CALLBACK_WHITELIST(/home/ghelling/.ansible.cfg) = ['timer', 'profile_tasks']
DEFAULT_FORKS(/home/ghelling/.ansible.cfg) = 10
DEFAULT_STDOUT_CALLBACK(/home/ghelling/.ansible.cfg) = yaml
HOST_KEY_CHECKING(/home/ghelling/.ansible.cfg) = False

##### OS / ENVIRONMENT
N/A

##### EXPECTED RESULTS
Module properly sets a valid SSH pubkey

##### ACTUAL RESULTS
```
failed: [test-passwordless_ssh2] (item=test-passwordless_ssh2) => {"changed": false, "item": "test-passwordless_ssh2", "msg": "Host parameter does not match hashed host field in supplied key"}
```

known_hosts module fails to set values with spurious error message
##### SUMMARY
The `known_hosts` module, when run in its default mode of adding entries to a file, fails with the error message "Host parameter does not match hashed host field in supplied key". This is not due to a problem with the key itself but rather in the way that the module writes the test file.

##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
known_hosts

##### ANSIBLE VERSION
```
ansible 2.6.1
  config file = /home/ghelling/.ansible.cfg
  configured module search path = [u'/home/ghelling/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /home/ghelling/venv/tools/lib/python2.7/site-packages/ansible
  executable location = /home/ghelling/venv/tools/bin/ansible
  python version = 2.7.15 (default, May 16 2018, 17:50:09) [GCC 8.1.1 20180502 (Red Hat 8.1.1-1)]
```

##### CONFIGURATION
ANSIBLE_PIPELINING(/home/ghelling/.ansible.cfg) = True
ANSIBLE_SSH_ARGS(/home/ghelling/.ansible.cfg) = -o ControlMaster=auto -o ControlPersist=600s -o Identiti>
ANSIBLE_SSH_CONTROL_PATH(/home/ghelling/.ansible.cfg) = %(directory)s/%%h-%%r
ANSIBLE_SSH_CONTROL_PATH_DIR(/home/ghelling/.ansible.cfg) = /tmp
DEFAULT_CALLBACK_WHITELIST(/home/ghelling/.ansible.cfg) = ['timer', 'profile_tasks']
DEFAULT_FORKS(/home/ghelling/.ansible.cfg) = 10
DEFAULT_STDOUT_CALLBACK(/home/ghelling/.ansible.cfg) = yaml
HOST_KEY_CHECKING(/home/ghelling/.ansible.cfg) = False

##### OS / ENVIRONMENT
N/A

##### EXPECTED RESULTS
Module properly sets a valid SSH pubkey

##### ACTUAL RESULTS
```
failed: [test-passwordless_ssh2] (item=test-passwordless_ssh2) => {"changed": false, "item": "test-passwordless_ssh2", "msg": "Host parameter does not match hashed host field in supplied key"}
```



Discussion:
Files identified in the description:
* [lib/ansible/modules/system/known_hosts.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/system/known_hosts.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @mcv21
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
Files identified in the description:
* [lib/ansible/modules/system/known_hosts.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/system/known_hosts.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @mcv21
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->

Resolving patch:
diff --git a/lib/ansible/modules/system/known_hosts.py b/lib/ansible/modules/system/known_hosts.py
--- a/lib/ansible/modules/system/known_hosts.py
+++ b/lib/ansible/modules/system/known_hosts.py
@@ -31,7 +31,11 @@
   key:
     description:
       - The SSH public host key, as a string (required if state=present, optional when state=absent, in which case all keys for the host are removed).
-        The key must be in the right format for ssh (see sshd(8), section "SSH_KNOWN_HOSTS FILE FORMAT")
+        The key must be in the right format for ssh (see sshd(8), section "SSH_KNOWN_HOSTS FILE FORMAT").
+
+        Specifically, the key should not match the format that is found in an SSH pubkey file, but should rather have the hostname prepended to a
+        line that includes the pubkey, the same way that it would appear in the known_hosts file. The value prepended to the line must also match
+        the value of the name parameter.
   path:
     description:
       - The known_hosts file to edit


Test patch:
diff --git a/test/units/modules/system/test_known_hosts.py b/test/units/modules/system/test_known_hosts.py
--- a/test/units/modules/system/test_known_hosts.py
+++ b/test/units/modules/system/test_known_hosts.py
@@ -1,10 +1,12 @@
 import os
 import tempfile
+import ansible.module_utils.basic as basic
 
 from ansible.compat.tests import unittest
 from ansible.module_utils._text import to_bytes
+from ansible.module_utils.basic import AnsibleModule
 
-from ansible.modules.system.known_hosts import compute_diff
+from ansible.modules.system.known_hosts import compute_diff, sanity_check
 
 
 class KnownHostsDiffTestCase(unittest.TestCase):
@@ -94,3 +96,12 @@ def test_key_removal_no_change(self):
             'before': 'two.example.com ssh-rsa BBBBetc\n',
             'after': 'two.example.com ssh-rsa BBBBetc\n',
         })
+
+    def test_sanity_check(self):
+        basic._load_params = lambda: {}
+        # Module used internally to execute ssh-keygen system executable
+        module = AnsibleModule(argument_spec={})
+        host = '10.0.0.1'
+        key = '%s ssh-rsa ASDF foo@bar' % (host,)
+        keygen = module.get_bin_path('ssh-keygen')
+        sanity_check(module, host, key, keygen)