Answers: <p>It seems that the issue you've filed, Ansible Issue #<a href="https://github.com/ansible/ansible/issues/78598" rel="nofollow noreferrer">78598</a> was noticed. It was possible to reproduce, got <a href="https://github.com/ansible/ansible/issues/78598#issuecomment-1225872041" rel="nofollow noreferrer">a small fix</a> and an <code>easyfix</code> label.</p>
  <p>Since further verification and testing is outstanding, you might be able to <a href="https://github.com/ansible/ansible/issues/78598#issuecomment-1225872041" rel="nofollow noreferrer">add the three proposed lines of code</a> into your own <code>known_host.py</code> and test it. You could provide after testing an update on the Ansible Issue.</p>
  
Answers: CC BY-SA 4.0
Answers: 2022-09-03T18:49:24.990Z
Answers: 2022-09-03T18:49:24.990Z
Answers: U880D
Body: <p>Why does my task report say that it has changed when nothing has changed?</p>
  <pre class="lang-yaml prettyprint-override"><code>- hosts: localhost
    become: false
    gather_facts: false
    tasks:
      - name: Remove non existing host key from known_hosts file
        known_hosts:
          name: 192.168.122.230
          key: 192.168.122.230 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCbi2hyrvpTRKC37NOm46n4zCPBb9r6cKk8BPrN2eppFu/0PJlB4D+nRI5epHzs5+1LhPkppbOGLC2VIRl3phMDQci3RIszhEZx4lAyX/HAkM+2zdNJlH2WWs3cbw804B4iqfCvy/Gch5ZXl4qEfpVqMURCr/XjaMQETzbjbfgOoyYxw8M/5Kq8VQy+DzqxNNzPi4ElcFQztxxrKDFPwuDplFdxw3YK+iQ4JHxlLWSfgtwsFhg7Z7uM8/efP7ocB23i2GmmG67yM/T/8uAld9t73V8icfe9WnRk2WVY69p4TzC3tMl2KmUDVm5AwvH+FNm/67E9t2inWHgKZacdOaOrgJ7SimPz0ILYDKd4hXg4whz3vdp21M/acjX3jA+fiwx6/GDIofKhyWOP3SwaiprqHZb+rWxerIOZx1IeuIRDZBH5Hjz7UlE5yg1xnqPXXzrFMj9rsKp9S5VB3HGGDfuOU7VymhZiTHIAuGM+weV6r2cOjn5HgdqkU6ABuchMAJvzaj9a3E07Rzk6h/lgWfy5VT/yl7DA7sM0/YSqKPJKgxbstoaOAZl35SDxAx978T0xlomIxaJUehRefK+G1GgPeLMmk0QtpX1dMH8bD4qvKGoLQG1qeJ4W4HrnoTsGLCxsN5/ek3rnqCekYOSiJ/q9+sZyhcLN1hwrDrrFK5fRUw==
          state: absent
        register: reg_known_hosts
       
      - name: Show known_host register
        debug:
          var: reg_known_hosts
  </code></pre>
  <pre><code>TASK [Remove non existing host key from known_hosts file] ***************************************
  changed: [localhost]
  
  TASK [Show known_hosts register] ****************************************************************
  ok: [localhost] =&gt; {
      &quot;reg_known_hosts&quot;: {
          &quot;changed&quot;: true,
          &quot;diff&quot;: {
              &quot;after&quot;: &quot;192.168.122.230 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIzlnSq5ESxLgW0avvPk3j7zLV59hcAPkxrMNdnZMKP2\n&quot;,
              &quot;after_header&quot;: &quot;/home/sxkx/.ssh/known_hosts&quot;,
              &quot;before&quot;: &quot;192.168.122.230 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIzlnSq5ESxLgW0avvPk3j7zLV59hcAPkxrMNdnZMKP2\n&quot;,
              &quot;before_header&quot;: &quot;/home/sxkx/.ssh/known_hosts&quot;
          },
          &quot;failed&quot;: false,
          &quot;gid&quot;: 1000,
          &quot;group&quot;: &quot;sxkx&quot;,
          &quot;hash_host&quot;: false,
          &quot;key&quot;: &quot;192.168.122.230 ssh-rsa ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCbi2hyrvpTRKC37NOm46n4zCPBb9r6cKk8BPrN2eppFu/0PJlB4D+nRI5epHzs5+1LhPkppbOGLC2VIRl3phMDQci3RIszhEZx4lAyX/HAkM+2zdNJlH2WWs3cbw804B4iqfCvy/Gch5ZXl4qEfpVqMURCr/XjaMQETzbjbfgOoyYxw8M/5Kq8VQy+DzqxNNzPi4ElcFQztxxrKDFPwuDplFdxw3YK+iQ4JHxlLWSfgtwsFhg7Z7uM8/efP7ocB23i2GmmG67yM/T/8uAld9t73V8icfe9WnRk2WVY69p4TzC3tMl2KmUDVm5AwvH+FNm/67E9t2inWHgKZacdOaOrgJ7SimPz0ILYDKd4hXg4whz3vdp21M/acjX3jA+fiwx6/GDIofKhyWOP3SwaiprqHZb+rWxerIOZx1IeuIRDZBH5Hjz7UlE5yg1xnqPXXzrFMj9rsKp9S5VB3HGGDfuOU7VymhZiTHIAuGM+weV6r2cOjn5HgdqkU6ABuchMAJvzaj9a3E07Rzk6h/lgWfy5VT/yl7DA7sM0/YSqKPJKgxbstoaOAZl35SDxAx978T0xlomIxaJUehRefK+G1GgPeLMmk0QtpX1dMH8bD4qvKGoLQG1qeJ4W4HrnoTsGLCxsN5/ek3rnqCekYOSiJ/q9+sZyhcLN1hwrDrrFK5fRUw==&quot;,
          &quot;mode&quot;: &quot;0600&quot;,
          &quot;name&quot;: &quot;192.168.122.230&quot;,
          &quot;owner&quot;: &quot;sxkx&quot;,
          &quot;path&quot;: &quot;/home/sxkx/.ssh/known_hosts&quot;,
          &quot;size&quot;: 97,
          &quot;state&quot;: &quot;file&quot;,
          &quot;uid&quot;: 1000
      }
  }
  </code></pre>
  <p>When looking at the register it says in the <code>diff</code> property that <code>before</code> and <code>after</code> are the same, yet it reports that it made changes?</p>
  <p>Something else I found out is that if I completely empty my <code>.ssh/known_hosts</code> file and run the playbook it will say <code>ok: [localhost]</code>.</p>
  <p>What I'm thinking is, is that when I specify a key to remove it will look for all the keys belonging to a particular host, making sure it does not contain the key in question but the before/after still holds a key (the ed25519 key) and then marks it as changed? It looks like when removing a key, the <code>known_hosts</code> module is expecting that all keys will be removed.</p>
  <p>I can work around it by using the <code>changed_when</code> property but I rather understand why Ansible is saying it changed when it did not change at all.</p>
  <p>This will work around the issue I'm having:</p>
  <pre class="lang-yaml prettyprint-override"><code>- name: Remove non existing host key from known_hosts file
    known_hosts:
      name: 192.168.122.230
      key: 192.168.122.230 ssh-rsa ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCbi2hyrvpTRKC37NOm46n4zCPBb9r6cKk8BPrN2eppFu/0PJlB4D+nRI5epHzs5+1LhPkppbOGLC2VIRl3phMDQci3RIszhEZx4lAyX/HAkM+2zdNJlH2WWs3cbw804B4iqfCvy/Gch5ZXl4qEfpVqMURCr/XjaMQETzbjbfgOoyYxw8M/5Kq8VQy+DzqxNNzPi4ElcFQztxxrKDFPwuDplFdxw3YK+iQ4JHxlLWSfgtwsFhg7Z7uM8/efP7ocB23i2GmmG67yM/T/8uAld9t73V8icfe9WnRk2WVY69p4TzC3tMl2KmUDVm5AwvH+FNm/67E9t2inWHgKZacdOaOrgJ7SimPz0ILYDKd4hXg4whz3vdp21M/acjX3jA+fiwx6/GDIofKhyWOP3SwaiprqHZb+rWxerIOZx1IeuIRDZBH5Hjz7UlE5yg1xnqPXXzrFMj9rsKp9S5VB3HGGDfuOU7VymhZiTHIAuGM+weV6r2cOjn5HgdqkU6ABuchMAJvzaj9a3E07Rzk6h/lgWfy5VT/yl7DA7sM0/YSqKPJKgxbstoaOAZl35SDxAx978T0xlomIxaJUehRefK+G1GgPeLMmk0QtpX1dMH8bD4qvKGoLQG1qeJ4W4HrnoTsGLCxsN5/ek3rnqCekYOSiJ/q9+sZyhcLN1hwrDrrFK5fRUw==
      state: absent
    register: reg_known_hosts
    changed_when: reg_known_hosts.diff.before != reg_known_hosts.diff.after
  </code></pre>
  <p>Ansible version: <code>ansible [core 2.13.2]</code></p>
  <p>What is going on here?</p>
  <p><strong>UPDATE - 18-Aug-2022</strong></p>
  <p>I will start by saying that I'm new to Ansible and I'm not a Python programmer.</p>
  <p>When reading the source code for the <code>known_hosts</code> module I found the following.</p>
  <p><code>Line: 228</code></p>
  <pre class="lang-py prettyprint-override"><code>def search_for_host_key(module, host, key, path, sshkeygen):
    '''search_for_host_key(module,host,key,path,sshkeygen) -&gt; (found,replace_or_add,found_line)
    Looks up host and keytype in the known_hosts file path; if it's there, looks to see
    if one of those entries matches key. Returns:
    found (Boolean): is host found in path?
    replace_or_add (Boolean): is the key in path different to that supplied by user?
    found_line (int or None): the line where a key of the same type was found
    if found=False, then replace is always False.
    sshkeygen is the path to ssh-keygen, found earlier with get_bin_path
    '''
  # ...
  </code></pre>
  <p>Looking at the comment at the top of the function I can conclude that:</p>
  <ul>
  <li><code>found</code> will equal <code>True</code> because I have a key for that host (key of type <code>ed25519</code>).</li>
  <li><code>replace_or_add</code> will equal <code>True</code> because the <code>key</code> is different from the one found (key of type <code>ed25519</code>).</li>
  <li><code>found_line</code> will be <code>None</code> because no key of the same type was found.</li>
  </ul>
  <p>With that in mind I think we can have a look at the <code>enforce_state</code> function.</p>
  <p><code>Line: 117</code></p>
  <pre class="lang-py prettyprint-override"><code>def enforce_state(module, params):
  
    # ...
  
    # Next, add a new (or replacing) entry
    if replace_or_add or found != (state == &quot;present&quot;):
      try:
        inf = open(path, &quot;r&quot;)
      except IOError as e:
        if e.errno == errno.ENOENT:
          inf = None
        else:
          module.fail_json(msg=&quot;Failed to read %s: %s&quot; % (path, str(e)))
      try:
        with tempfile.NamedTemporaryFile(mode='w+', dir=os.path.dirname(path), delete=False) as outf:
          if inf is not None:
            for line_number, line in enumerate(inf):
              if found_line == (line_number + 1) and (replace_or_add or state == 'absent'):
                continue  # skip this line to replace its key
              outf.write(line)
            inf.close()
          if state == 'present':
            outf.write(key)
      except (IOError, OSError) as e:
        module.fail_json(msg=&quot;Failed to write to file %s: %s&quot; % (path, to_native(e)))
      else:
        module.atomic_move(outf.name, path)
  
      params['changed'] = True
  </code></pre>
  <p>I think the culprit lies within this if block. For what I could make up from the comment in the previous function; <code>replace_or_add</code> is <code>True</code>, <code>found</code> is <code>True</code> and not equal to <code>state == &quot;present&quot;</code>. Within this if block it will read the <code>known_hosts</code> file and loops over the lines and when a line (number) matches the <code>found_line</code> it will continue the loop, otherwise it will write that line to (a temporary) file. However no matter what it does within the loop, later on in the if block it will always set <code>params['changed'] = True</code>, meaning it will always report <code>changed</code> regardless of there actually being changes. A possible solution to this could be a counter to keep track of the number of times the loop was continued and then set the <code>params</code> variable property like so: <code>params['changed'] = True if counter &gt; 0 else False</code>.</p>
  <p>Something else I think is happening (regardless of changes) is that it will perform a write operation. If so then yes it would make some sense (would it?) that <code>params['changed']</code> is set to <code>True</code> but I would much rather see the module only write out to <code>.ssh/known_hosts</code> if something actually changed.</p>
  <p><strong>UPDATE - 19-Aug-2022</strong></p>
  <p>This portion is not related to the state always being <code>changed</code> but rather something to do with the <code>hash_host</code> option in the <code>known_hosts</code> module, either your hostname or IP is lost and not set in the <code>known_hosts</code> file.</p>
  <p>Let's assume the following entry is in my <code>known_hosts</code> file.</p>
  <pre><code>host.local,192.168.122.230 ssh-rsa &lt;public_key&gt;
  </code></pre>
  <p>When hashing the <code>known_hosts</code> file with <code>ssh-keygen -H</code> it represents the line above like so.</p>
  <pre><code>|1|&lt;salt&gt;|&lt;hash&gt; ssh-rsa &lt;public_key&gt;
  |1|&lt;salt&gt;|&lt;hash&gt; ssh-rsa &lt;public_key&gt;
  </code></pre>
  <p>Where the first line is for <code>host.local</code> and the second line is for <code>192.168.122.230</code>.</p>
  <p>When attempting the same thing with the <code>known_hosts</code> module in Ansible something different will happen.</p>
  <pre class="lang-yaml prettyprint-override"><code>- name: add host key to known_hosts file
    known_hosts:
      name: host.local
      key: host.local,192.168.122.230 ssh-rsa &lt;public_key&gt;
      state: present
  </code></pre>
  <p>Will result in the following entry in the <code>known_hosts</code> file.</p>
  <pre><code>host.local,192.168.122.230 ssh-rsa &lt;public_key&gt;
  </code></pre>
  <p>However when you enable hashing things will change.</p>
  <pre class="lang-yaml prettyprint-override"><code>- name: add host key to known_hosts file
    known_hosts:
      hash_host: yes
      name: host.local
      key: host.local,192.168.122.230 ssh-rsa &lt;public_key&gt;
      state: present
  </code></pre>
  <pre><code>|1|&lt;salt&gt;|&lt;hash&gt; ssh-rsa &lt;public_key&gt;
  </code></pre>
  <p>It will have only hashed the entry for <code>host.local</code> the IP version of that line is just gone. This is something to keep in mind when you want to use both the hostname and IP to access the target.</p>
  <p><strong>UPDATE: 24-Aug-2022</strong></p>
  <p>Opened an <a href="https://github.com/ansible/ansible/issues/78598" rel="nofollow noreferrer">issue</a> over on the Ansible github.</p>
  <p>If you find any information to be incorrect please let me know or edit this post.</p>
  
Comments: CC BY-SA 4.0
Comments: 2022-08-16T19:38:00.790Z
Comments: Strange format of `'key: 192.168.122.230 ssh-rsa ssh-rsa AAAAB3NzaC1yc....'` Isn't it?
Comments: Vladimir Botka
Comments: CC BY-SA 4.0
Comments: 2022-08-16T20:04:36.723Z
Comments: Yes, my bad. Messed it up while copying in the public key. Will change it right away. My issue remains though.
Comments: sxkx
Comments: CC BY-SA 4.0
Comments: 2022-08-16T20:26:21.867Z
Comments: [Debugging modules](https://docs.ansible.com/ansible/latest/dev_guide/debugging.html#debugging-modules) will be needed to find out what is going on here, I guess.
Comments: Vladimir Botka
Comments: CC BY-SA 4.0
Comments: 2022-08-16T20:27:46.737Z
Comments: Yes, I'm reading the source code right now and I think it is a bug (or some behaviour I do not understand). Will update my question in a bit.
Comments: sxkx
Comments: CC BY-SA 4.0
Comments: 2022-08-16T20:32:15.140Z
Comments: I read it too. I've already seen better, e.g. why mandatory host when the host is in the key? No sanity checking of the keys, strange complex conditions, ...
Comments: Vladimir Botka
Comments: CC BY-SA 4.0
Comments: 2022-08-16T20:37:15.397Z
Comments: You might want to briefly check with [#ansible](https://docs.ansible.com/ansible/latest/community/communication.html#general-channels) what the guys think about it.
Comments: Vladimir Botka
Comments: CC BY-SA 4.0
Comments: 2022-08-17T09:05:29.743Z
Comments: Can you double check the permissions of the file 644 vs 600 (before the change)?
Comments: Kyslik
Comments: CC BY-SA 4.0
Comments: 2022-08-17T14:33:53.757Z
Comments: Okay back at it, I tried both file permissions but the same thing happens.
Comments: sxkx
Comments: CC BY-SA 4.0
Comments: 2022-08-18T18:54:48.347Z
Comments: @VladimirBotka updated my question, took a bit trying to figure out what was going on with the `hash_host` option in the `known_hosts` module.
Comments: sxkx
Tags: <ansible>
Title: known_hosts module reports changed when nothing has changed
UserDisplayName: sxkx
ThreadText: # known_hosts module reports changed when nothing has changed
  
  (Asked by: username_0 on 2022-08-16)
  
  Why does my task report say that it has changed when nothing has changed?
  
  ```yaml
  - hosts: localhost
    become: false
    gather_facts: false
    tasks:
      - name: Remove non existing host key from known_hosts file
        known_hosts:
          name: 192.168.122.230
          key: 192.168.122.230 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCbi2hyrvpTRKC37NOm46n4zCPBb9r6cKk8BPrN2eppFu/0PJlB4D+nRI5epHzs5+1LhPkppbOGLC2VIRl3phMDQci3RIszhEZx4lAyX/HAkM+2zdNJlH2WWs3cbw804B4iqfCvy/Gch5ZXl4qEfpVqMURCr/XjaMQETzbjbfgOoyYxw8M/5Kq8VQy+DzqxNNzPi4ElcFQztxxrKDFPwuDplFdxw3YK+iQ4JHxlLWSfgtwsFhg7Z7uM8/efP7ocB23i2GmmG67yM/T/8uAld9t73V8icfe9WnRk2WVY69p4TzC3tMl2KmUDVm5AwvH+FNm/67E9t2inWHgKZacdOaOrgJ7SimPz0ILYDKd4hXg4whz3vdp21M/acjX3jA+fiwx6/GDIofKhyWOP3SwaiprqHZb+rWxerIOZx1IeuIRDZBH5Hjz7UlE5yg1xnqPXXzrFMj9rsKp9S5VB3HGGDfuOU7VymhZiTHIAuGM+weV6r2cOjn5HgdqkU6ABuchMAJvzaj9a3E07Rzk6h/lgWfy5VT/yl7DA7sM0/YSqKPJKgxbstoaOAZl35SDxAx978T0xlomIxaJUehRefK+G1GgPeLMmk0QtpX1dMH8bD4qvKGoLQG1qeJ4W4HrnoTsGLCxsN5/ek3rnqCekYOSiJ/q9+sZyhcLN1hwrDrrFK5fRUw==
          state: absent
        register: reg_known_hosts
       
      - name: Show known_host register
        debug:
          var: reg_known_hosts
  
  ```
  
  ```
  TASK [Remove non existing host key from known_hosts file] ***************************************
  changed: [localhost]
  
  TASK [Show known_hosts register] ****************************************************************
  ok: [localhost] => {
      "reg_known_hosts": {
          "changed": true,
          "diff": {
              "after": "192.168.122.230 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIzlnSq5ESxLgW0avvPk3j7zLV59hcAPkxrMNdnZMKP2\n",
              "after_header": "/home/username_0/.ssh/known_hosts",
              "before": "192.168.122.230 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIzlnSq5ESxLgW0avvPk3j7zLV59hcAPkxrMNdnZMKP2\n",
              "before_header": "/home/username_0/.ssh/known_hosts"
          },
          "failed": false,
          "gid": 1000,
          "group": "username_0",
          "hash_host": false,
          "key": "192.168.122.230 ssh-rsa ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCbi2hyrvpTRKC37NOm46n4zCPBb9r6cKk8BPrN2eppFu/0PJlB4D+nRI5epHzs5+1LhPkppbOGLC2VIRl3phMDQci3RIszhEZx4lAyX/HAkM+2zdNJlH2WWs3cbw804B4iqfCvy/Gch5ZXl4qEfpVqMURCr/XjaMQETzbjbfgOoyYxw8M/5Kq8VQy+DzqxNNzPi4ElcFQztxxrKDFPwuDplFdxw3YK+iQ4JHxlLWSfgtwsFhg7Z7uM8/efP7ocB23i2GmmG67yM/T/8uAld9t73V8icfe9WnRk2WVY69p4TzC3tMl2KmUDVm5AwvH+FNm/67E9t2inWHgKZacdOaOrgJ7SimPz0ILYDKd4hXg4whz3vdp21M/acjX3jA+fiwx6/GDIofKhyWOP3SwaiprqHZb+rWxerIOZx1IeuIRDZBH5Hjz7UlE5yg1xnqPXXzrFMj9rsKp9S5VB3HGGDfuOU7VymhZiTHIAuGM+weV6r2cOjn5HgdqkU6ABuchMAJvzaj9a3E07Rzk6h/lgWfy5VT/yl7DA7sM0/YSqKPJKgxbstoaOAZl35SDxAx978T0xlomIxaJUehRefK+G1GgPeLMmk0QtpX1dMH8bD4qvKGoLQG1qeJ4W4HrnoTsGLCxsN5/ek3rnqCekYOSiJ/q9+sZyhcLN1hwrDrrFK5fRUw==",
          "mode": "0600",
          "name": "192.168.122.230",
          "owner": "username_0",
          "path": "/home/username_0/.ssh/known_hosts",
          "size": 97,
          "state": "file",
          "uid": 1000
      }
  }
  
  ```
  
  When looking at the register it says in the `diff` property that `before` and `after` are the same, yet it reports that it made changes?
  
  Something else I found out is that if I completely empty my `.ssh/known_hosts` file and run the playbook it will say `ok: [localhost]`.
  
  What I'm thinking is, is that when I specify a key to remove it will look for all the keys belonging to a particular host, making sure it does not contain the key in question but the before/after still holds a key (the ed25519 key) and then marks it as changed? It looks like when removing a key, the `known_hosts` module is expecting that all keys will be removed.
  
  I can work around it by using the `changed_when` property but I rather understand why Ansible is saying it changed when it did not change at all.
  
  This will work around the issue I'm having:
  
  ```yaml
  - name: Remove non existing host key from known_hosts file
    known_hosts:
      name: 192.168.122.230
      key: 192.168.122.230 ssh-rsa ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCbi2hyrvpTRKC37NOm46n4zCPBb9r6cKk8BPrN2eppFu/0PJlB4D+nRI5epHzs5+1LhPkppbOGLC2VIRl3phMDQci3RIszhEZx4lAyX/HAkM+2zdNJlH2WWs3cbw804B4iqfCvy/Gch5ZXl4qEfpVqMURCr/XjaMQETzbjbfgOoyYxw8M/5Kq8VQy+DzqxNNzPi4ElcFQztxxrKDFPwuDplFdxw3YK+iQ4JHxlLWSfgtwsFhg7Z7uM8/efP7ocB23i2GmmG67yM/T/8uAld9t73V8icfe9WnRk2WVY69p4TzC3tMl2KmUDVm5AwvH+FNm/67E9t2inWHgKZacdOaOrgJ7SimPz0ILYDKd4hXg4whz3vdp21M/acjX3jA+fiwx6/GDIofKhyWOP3SwaiprqHZb+rWxerIOZx1IeuIRDZBH5Hjz7UlE5yg1xnqPXXzrFMj9rsKp9S5VB3HGGDfuOU7VymhZiTHIAuGM+weV6r2cOjn5HgdqkU6ABuchMAJvzaj9a3E07Rzk6h/lgWfy5VT/yl7DA7sM0/YSqKPJKgxbstoaOAZl35SDxAx978T0xlomIxaJUehRefK+G1GgPeLMmk0QtpX1dMH8bD4qvKGoLQG1qeJ4W4HrnoTsGLCxsN5/ek3rnqCekYOSiJ/q9+sZyhcLN1hwrDrrFK5fRUw==
      state: absent
    register: reg_known_hosts
    changed_when: reg_known_hosts.diff.before != reg_known_hosts.diff.after
  
  ```
  
  Ansible version: `ansible [core 2.13.2]`
  
  What is going on here?
  
  **UPDATE - 18-Aug-2022**
  
  I will start by saying that I'm new to Ansible and I'm not a Python programmer.
  
  When reading the source code for the `known_hosts` module I found the following.
  
  `Line: 228`
  
  ```py
  def search_for_host_key(module, host, key, path, sshkeygen):
    '''search_for_host_key(module,host,key,path,sshkeygen) -> (found,replace_or_add,found_line)
    Looks up host and keytype in the known_hosts file path; if it's there, looks to see
    if one of those entries matches key. Returns:
    found (Boolean): is host found in path?
    replace_or_add (Boolean): is the key in path different to that supplied by user?
    found_line (int or None): the line where a key of the same type was found
    if found=False, then replace is always False.
    sshkeygen is the path to ssh-keygen, found earlier with get_bin_path
    '''
  # ...
  
  ```
  
  Looking at the comment at the top of the function I can conclude that:
  
  * `found` will equal `True` because I have a key for that host (key of type `ed25519`).
  * `replace_or_add` will equal `True` because the `key` is different from the one found (key of type `ed25519`).
  * `found_line` will be `None` because no key of the same type was found.
  
  With that in mind I think we can have a look at the `enforce_state` function.
  
  `Line: 117`
  
  ```py
  def enforce_state(module, params):
  
    # ...
  
    # Next, add a new (or replacing) entry
    if replace_or_add or found != (state == "present"):
      try:
        inf = open(path, "r")
      except IOError as e:
        if e.errno == errno.ENOENT:
          inf = None
        else:
          module.fail_json(msg="Failed to read %s: %s" % (path, str(e)))
      try:
        with tempfile.NamedTemporaryFile(mode='w+', dir=os.path.dirname(path), delete=False) as outf:
          if inf is not None:
            for line_number, line in enumerate(inf):
              if found_line == (line_number + 1) and (replace_or_add or state == 'absent'):
                continue  # skip this line to replace its key
              outf.write(line)
            inf.close()
          if state == 'present':
            outf.write(key)
      except (IOError, OSError) as e:
        module.fail_json(msg="Failed to write to file %s: %s" % (path, to_native(e)))
      else:
        module.atomic_move(outf.name, path)
  
      params['changed'] = True
  
  ```
  
  I think the culprit lies within this if block. For what I could make up from the comment in the previous function; `replace_or_add` is `True`, `found` is `True` and not equal to `state == "present"`. Within this if block it will read the `known_hosts` file and loops over the lines and when a line (number) matches the `found_line` it will continue the loop, otherwise it will write that line to (a temporary) file. However no matter what it does within the loop, later on in the if block it will always set `params['changed'] = True`, meaning it will always report `changed` regardless of there actually being changes. A possible solution to this could be a counter to keep track of the number of times the loop was continued and then set the `params` variable property like so: `params['changed'] = True if counter > 0 else False`.
  
  Something else I think is happening (regardless of changes) is that it will perform a write operation. If so then yes it would make some sense (would it?) that `params['changed']` is set to `True` but I would much rather see the module only write out to `.ssh/known_hosts` if something actually changed.
  
  **UPDATE - 19-Aug-2022**
  
  This portion is not related to the state always being `changed` but rather something to do with the `hash_host` option in the `known_hosts` module, either your hostname or IP is lost and not set in the `known_hosts` file.
  
  Let's assume the following entry is in my `known_hosts` file.
  
  ```
  host.local,192.168.122.230 ssh-rsa <public_key>
  
  ```
  
  When hashing the `known_hosts` file with `ssh-keygen -H` it represents the line above like so.
  
  ```
  |1|<salt>|<hash> ssh-rsa <public_key>
  |1|<salt>|<hash> ssh-rsa <public_key>
  
  ```
  
  Where the first line is for `host.local` and the second line is for `192.168.122.230`.
  
  When attempting the same thing with the `known_hosts` module in Ansible something different will happen.
  
  ```yaml
  - name: add host key to known_hosts file
    known_hosts:
      name: host.local
      key: host.local,192.168.122.230 ssh-rsa <public_key>
      state: present
  
  ```
  
  Will result in the following entry in the `known_hosts` file.
  
  ```
  host.local,192.168.122.230 ssh-rsa <public_key>
  
  ```
  
  However when you enable hashing things will change.
  
  ```yaml
  - name: add host key to known_hosts file
    known_hosts:
      hash_host: yes
      name: host.local
      key: host.local,192.168.122.230 ssh-rsa <public_key>
      state: present
  
  ```
  
  ```
  |1|<salt>|<hash> ssh-rsa <public_key>
  
  ```
  
  It will have only hashed the entry for `host.local` the IP version of that line is just gone. This is something to keep in mind when you want to use both the hostname and IP to access the target.
  
  **UPDATE: 24-Aug-2022**
  
  Opened an [issue](https://github.com/ansible/ansible/issues/78598) over on the Ansible github.
  
  If you find any information to be incorrect please let me know or edit this post.
  
  **Tags:** ansible
  
  > **Comments:**
  > **username_1**: Strange format of `'key: 192.168.122.230 ssh-rsa ssh-rsa AAAAB3NzaC1yc....'` Isn't it?  
  > **username_0**: Yes, my bad. Messed it up while copying in the public key. Will change it right away. My issue remains though.  
  > **username_1**: [Debugging modules](https://docs.ansible.com/ansible/latest/dev_guide/debugging.html#debugging-modules) will be needed to find out what is going on here, I guess.  
  > **username_0**: Yes, I'm reading the source code right now and I think it is a bug (or some behaviour I do not understand). Will update my question in a bit.  
  > **username_1**: I read it too. I've already seen better, e.g. why mandatory host when the host is in the key? No sanity checking of the keys, strange complex conditions, ...  
  > **username_1**: You might want to briefly check with [#ansible](https://docs.ansible.com/ansible/latest/community/communication.html#general-channels) what the guys think about it.  
  > **username_2**: Can you double check the permissions of the file 644 vs 600 (before the change)?  
  > **username_0**: Okay back at it, I tried both file permissions but the same thing happens.  
  > **username_0**: @username_1 updated my question, took a bit trying to figure out what was going on with the `hash_host` option in the `known_hosts` module.  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_3 on 2022-09-03. Score: 1
  
  It seems that the issue you've filed, Ansible Issue #[78598](https://github.com/ansible/ansible/issues/78598) was noticed. It was possible to reproduce, got [a small fix](https://github.com/ansible/ansible/issues/78598#issuecomment-1225872041) and an `easyfix` label.
  
  Since further verification and testing is outstanding, you might be able to [add the three proposed lines of code](https://github.com/ansible/ansible/issues/78598#issuecomment-1225872041) into your own `known_host.py` and test it. You could provide after testing an update on the Ansible Issue.
  
  
  ---
  
  