Skip to content

Commit

Permalink
Update known_hosts module to better handle @cert-authority keys
Browse files Browse the repository at this point in the history
  • Loading branch information
zoredache committed Jul 23, 2020
1 parent 5260527 commit 960ff40
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 9 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/known_hosts_cert-authority_keys.yml
@@ -0,0 +1,2 @@
bugfixes:
- known_hosts - Fix issue with `@cert-authority` entries in known_hosts incorrectly being removed.
20 changes: 14 additions & 6 deletions lib/ansible/modules/known_hosts.py
Expand Up @@ -260,12 +260,20 @@ def search_for_host_key(module, host, key, path, sshkeygen):
module.fail_json(msg="failed to parse output of ssh-keygen for line number: '%s'" % l)
else:
found_key = normalize_known_hosts_key(l)
if new_key['host'][:3] == '|1|' and found_key['host'][:3] == '|1|': # do not change host hash if already hashed
new_key['host'] = found_key['host']
if new_key == found_key: # found a match
return True, False, found_line # found exactly the same key, don't replace
elif new_key['type'] == found_key['type']: # found a different key for the same key type
return True, True, found_line

if 'options' in found_key and found_key['options'][:15] == '@cert-authority':
if new_key == found_key: # found a match
return True, False, found_line # found exactly the same key, don't replace
elif 'options' in found_key and found_key['options'][:7] == '@revoke':
if new_key == found_key: # found a match
return True, False, found_line # found exactly the same key, don't replace
else:
if new_key['host'][:3] == '|1|' and found_key['host'][:3] == '|1|': # do not change host hash if already hashed
new_key['host'] = found_key['host']
if new_key == found_key: # found a match
return True, False, found_line # found exactly the same key, don't replace
elif new_key['type'] == found_key['type']: # found a different key for the same key type
return True, True, found_line

# No match found, return found and replace, but no line
return True, True, None
Expand Down
6 changes: 6 additions & 0 deletions test/integration/targets/known_hosts/defaults/main.yml
@@ -1,3 +1,9 @@
---
example_org_rsa_key: >
example.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAglyZmHHWskQ9wkh8LYbIqzvg99/oloneH7BaZ02ripJUy/2Zynv4tgUfm9fdXvAb1XXCEuTRnts9FBer87+voU0FPRgx3CfY9Sgr0FspUjnm4lqs53FIab1psddAaS7/F7lrnjl6VqBtPwMRQZG7qlml5uogGJwYJHxX0PGtsdoTJsM=
host_example_com_ed25519_key: >
host.example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFp8VtD59XAcxkj1qbfCtB1in9nm5WiipORjtVJUBA6I
example_com_ed25519_ca: >
@cert-authority *.example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPx6KAHnQhaWdYQoaclJMWfneZckvYOkZ32gUJO1zzJK
host_example_com_ed25519_signedhost: >
host.example.com ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIHgrfzePvYcPiRDh/3yKt2sJBk6mftlLGPpAlgveY8amAAAAIE/humEfyhaw5kawq/RC8tOoVJFgu6v+AYV2koz4bULNAAAAAAAAAAAAAAACAAAAFGhvc3QuZXhhbXBsZS5jb20ucHViAAAAFAAAABBob3N0LmV4YW1wbGUuY29tAAAAAAAAAAD//////////wAAAAAAAAAAAAAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAg/HooAedCFpZ1hChpyUkxZ+d5lyS9g6RnfaBQk7XPMkoAAABTAAAAC3NzaC1lZDI1NTE5AAAAQPrSxFZ57dZvHy+ZqhudHBj5C1xU/aiAcMjbpyg3PwR/T/ym8B299uyhRj4g6wbby389xuTFkIYYgGlzh1vAkA0=
Expand Up @@ -2,4 +2,5 @@ example.com ssh-dss AAAAB3NzaC1kc3MAAACBALT8YHxZ59d8yX4oQNPbpdK9AMPRQGKFY9X13S2f
|1|d71/U7CbOH3Su+d2zxlbmiNfXtI=|g2YSPAVoK7bmg16FCOOPKTZe2BM= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|1|L0TqxOhAVh6mLZ2lbHdTv3owun0=|vn0La5pbHNxin3XzQQdvaOulvVU= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCNLCAA/SjVF3jkmlAlkgh+GtZdgxtusHaK66fcA7XSgCpQOdri1dGmND6pQDGwsxiKMy4Ou1GB2DR4N0G9T5E8=
|1|WPo7yAOdlQKLSuRatNJCmDoga0k=|D/QybGglKokWuEQUe9Okpy5uSh0= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCNLCAA/SjVF3jkmlAlkgh+GtZdgxtusHaK66fcA7XSgCpQOdri1dGmND6pQDGwsxiKMy4Ou1GB2DR4N0G9T5E8=
@cert-authority *.example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDXh1gk2xgS2MekPvo7ZEKiOT7HoyvOAzai2GqoLXGHO
# example.net ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM6OSqweGdPdQ/metQaf738AdN3P+itYp1AypOTgXkyj root@localhost
106 changes: 103 additions & 3 deletions test/integration/targets/known_hosts/tasks/main.yml
Expand Up @@ -57,7 +57,8 @@
that:
- 'result is changed'
- 'known_hosts.stdout_lines[0].startswith("example.com")'
- 'known_hosts.stdout_lines[4].startswith("# example.net")'
- 'known_hosts.stdout_lines[4].startswith("@cert-authority")'
- 'known_hosts.stdout_lines[5].startswith("# example.net")'
- 'known_hosts.stdout_lines[-1].strip() == example_org_rsa_key.strip()'

# test idempotence of addition
Expand Down Expand Up @@ -190,7 +191,7 @@
that:
- 'result is changed'
- 'known_hosts_v5.stdout_lines[0].startswith("example.com")'
- 'known_hosts_v5.stdout_lines[4].startswith("# example.net")'
- 'known_hosts_v5.stdout_lines[5].startswith("# example.net")'
- 'known_hosts_v5.stdout_lines[-1].strip().startswith("|1|")'
- 'known_hosts_v5.stdout_lines[-1].strip().endswith(example_org_rsa_key.strip().split()[-1])'

Expand Down Expand Up @@ -310,7 +311,7 @@
- name: assert the plaintext host is there
assert:
that:
- 'known_hosts_v10.stdout_lines[5].strip() == example_org_rsa_key.strip()'
- 'known_hosts_v10.stdout_lines[6].strip() == example_org_rsa_key.strip()'

# ... and remove the host again for the next test

Expand Down Expand Up @@ -346,6 +347,105 @@
that:
- 'known_hosts_v11.stdout_lines[-1].strip().endswith("RANDOM=")'

- name: add the ed25519 host key
known_hosts:
name: host.example.com
key: "{{ host_example_com_ed25519_key }}"
state: present
path: "{{output_dir}}/known_hosts"
register: result

- name: get the file content
command: "cat {{output_dir}}/known_hosts"
register: known_hosts_v12

- name: assert that the key was added and ordering preserved
assert:
that:
- 'result is changed'
- 'known_hosts_v12.stdout_lines[0].startswith("example.com")'
- 'known_hosts_v12.stdout_lines[4].startswith("@cert-authority")'
- 'known_hosts_v12.stdout_lines[5].startswith("# example.net")'
- 'known_hosts_v12.stdout_lines[-1].strip() == host_example_com_ed25519_key.strip()'

- name: add the ed25519 ca key
known_hosts:
name: '*.example.com'
key: "{{ example_com_ed25519_ca }}"
state: present
path: "{{output_dir}}/known_hosts"
register: result

- name: get the file content
command: "cat {{output_dir}}/known_hosts"
register: known_hosts_v13

- name: assert that the key was added and ordering preserved
assert:
that:
- 'result is changed'
- 'known_hosts_v13.stdout_lines[0].startswith("example.com")'
- 'known_hosts_v13.stdout_lines[4].startswith("@cert-authority")'
- 'known_hosts_v13.stdout_lines[5].startswith("# example.net")'
- 'known_hosts_v13.stdout_lines[-1].strip() == example_com_ed25519_ca.strip()'

- name: Remove the ed25519 ca key
known_hosts:
name: '*.example.com'
key: "{{ example_com_ed25519_ca }}"
state: absent
path: "{{output_dir}}/known_hosts"
register: result

- name: get the file content
command: "cat {{output_dir}}/known_hosts"
register: known_hosts_v14

- name: assert that the key was removed and ordering preserved
assert:
that:
- 'result is changed'
- 'known_hosts_v12.stdout == known_hosts_v14.stdout'

- name: add the revoked ed25519 host key
known_hosts:
name: 'host.example.com'
key: "@revoked {{ host_example_com_ed25519_signedhost }}"
state: present
path: "{{output_dir}}/known_hosts"
register: result

- name: get the file content
command: "cat {{output_dir}}/known_hosts"
register: known_hosts_v15

- name: assert that the key was added and ordering preserved
assert:
that:
- 'result is changed'
- 'known_hosts_v15.stdout_lines[0].startswith("example.com")'
- 'known_hosts_v15.stdout_lines[4].startswith("@cert-authority")'
- 'known_hosts_v15.stdout_lines[5].startswith("# example.net")'
- 'known_hosts_v15.stdout_lines[-1].strip() == "@revoked " ~ host_example_com_ed25519_signedhost.strip()'

- name: remove the revoked ed25519 host key
known_hosts:
name: 'host.example.com'
key: "@revoked {{ host_example_com_ed25519_signedhost }}"
state: absent
path: "{{output_dir}}/known_hosts"
register: result

- name: get the file content
command: "cat {{output_dir}}/known_hosts"
register: known_hosts_v16

- name: assert that the key was removed and ordering preserved
assert:
that:
- 'result is changed'
- 'known_hosts_v12.stdout == known_hosts_v16.stdout'

# test errors

- name: Try using a comma separated list of hosts
Expand Down

0 comments on commit 960ff40

Please sign in to comment.