Add comment option to authorized_key (#27781)

* Add comment option to authorized_keys

* Update version_added for authorized_keys comment

* PEP8

* Include index rank in parsed_key_key

*  Properly display diff

Only display diff if specificed via settings

* Fix PEP8 test failure

Removed from legacy files since it is now properly formatted

* Cleanup integration test formatting and add test for new comment feature

* Correct version_added for new option
This commit is contained in:
Sam Doran 2017-08-15 10:50:50 -04:00 committed by GitHub
parent 8a69706037
commit 271127113f
4 changed files with 234 additions and 152 deletions

View file

@ -79,6 +79,14 @@ options:
default: "yes" default: "yes"
choices: ["yes", "no"] choices: ["yes", "no"]
version_added: "2.1" version_added: "2.1"
comment:
description:
- Change the comment on the public key. Rewriting the comment is useful in
cases such as fetching it from GitHub or GitLab.
- If no comment is specified, the existing comment will be kept.
required: false
default: None
version_added: "2.4"
author: "Ansible Core Team" author: "Ansible Core Team"
''' '''
@ -220,6 +228,7 @@ from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.pycompat24 import get_exception from ansible.module_utils.pycompat24 import get_exception
from ansible.module_utils.urls import fetch_url from ansible.module_utils.urls import fetch_url
class keydict(dict): class keydict(dict):
""" a dictionary that maintains the order of keys as they are added """ a dictionary that maintains the order of keys as they are added
@ -247,8 +256,8 @@ class keydict(dict):
# http://stackoverflow.com/questions/2328235/pythonextend-the-dict-class # http://stackoverflow.com/questions/2328235/pythonextend-the-dict-class
def __init__(self, *args, **kw): def __init__(self, *args, **kw):
super(keydict,self).__init__(*args, **kw) super(keydict, self).__init__(*args, **kw)
self.itemlist = list(super(keydict,self).keys()) self.itemlist = list(super(keydict, self).keys())
def __setitem__(self, key, value): def __setitem__(self, key, value):
self.itemlist.append(key) self.itemlist.append(key)
@ -309,12 +318,12 @@ def keyfile(module, user, write=False, path=None, manage_dir=True):
module.fail_json(msg="Either user must exist or you must provide full path to key file in check mode") module.fail_json(msg="Either user must exist or you must provide full path to key file in check mode")
module.fail_json(msg="Failed to lookup user %s: %s" % (user, str(e))) module.fail_json(msg="Failed to lookup user %s: %s" % (user, str(e)))
if path is None: if path is None:
homedir = user_entry.pw_dir homedir = user_entry.pw_dir
sshdir = os.path.join(homedir, ".ssh") sshdir = os.path.join(homedir, ".ssh")
keysfile = os.path.join(sshdir, "authorized_keys") keysfile = os.path.join(sshdir, "authorized_keys")
else: else:
sshdir = os.path.dirname(path) sshdir = os.path.dirname(path)
keysfile = path keysfile = path
if not write: if not write:
return keysfile return keysfile
@ -335,7 +344,7 @@ def keyfile(module, user, write=False, path=None, manage_dir=True):
if not os.path.exists(basedir): if not os.path.exists(basedir):
os.makedirs(basedir) os.makedirs(basedir)
try: try:
f = open(keysfile, "w") #touches file so we can set ownership and perms f = open(keysfile, "w") # touches file so we can set ownership and perms
finally: finally:
f.close() f.close()
if module.selinux_enabled(): if module.selinux_enabled():
@ -349,12 +358,13 @@ def keyfile(module, user, write=False, path=None, manage_dir=True):
return keysfile return keysfile
def parseoptions(module, options): def parseoptions(module, options):
''' '''
reads a string containing ssh-key options reads a string containing ssh-key options
and returns a dictionary of those options and returns a dictionary of those options
''' '''
options_dict = keydict() #ordered dict options_dict = keydict() # ordered dict
if options: if options:
# the following regex will split on commas while # the following regex will split on commas while
# ignoring those commas that fall within quotes # ignoring those commas that fall within quotes
@ -369,6 +379,7 @@ def parseoptions(module, options):
return options_dict return options_dict
def parsekey(module, raw_key, rank=None): def parsekey(module, raw_key, rank=None):
''' '''
parses a key, which may or may not contain a list parses a key, which may or may not contain a list
@ -387,9 +398,9 @@ def parsekey(module, raw_key, rank=None):
'ssh-rsa', 'ssh-rsa',
] ]
options = None # connection options options = None # connection options
key = None # encrypted key string key = None # encrypted key string
key_type = None # type of ssh key key_type = None # type of ssh key
type_index = None # index of keytype in key string|list type_index = None # index of keytype in key string|list
# remove comment yaml escapes # remove comment yaml escapes
@ -398,7 +409,7 @@ def parsekey(module, raw_key, rank=None):
# split key safely # split key safely
lex = shlex.shlex(raw_key) lex = shlex.shlex(raw_key)
lex.quotes = [] lex.quotes = []
lex.commenters = '' #keep comment hashes lex.commenters = '' # keep comment hashes
lex.whitespace_split = True lex.whitespace_split = True
key_parts = list(lex) key_parts = list(lex)
@ -430,6 +441,7 @@ def parsekey(module, raw_key, rank=None):
return (key, key_type, options, comment, rank) return (key, key_type, options, comment, rank)
def readfile(filename): def readfile(filename):
if not os.path.isfile(filename): if not os.path.isfile(filename):
@ -441,6 +453,7 @@ def readfile(filename):
finally: finally:
f.close() f.close()
def parsekeys(module, lines): def parsekeys(module, lines):
keys = {} keys = {}
for rank_index, line in enumerate(lines.splitlines(True)): for rank_index, line in enumerate(lines.splitlines(True)):
@ -454,10 +467,11 @@ def parsekeys(module, lines):
keys[line] = (line, 'skipped', None, None, rank_index) keys[line] = (line, 'skipped', None, None, rank_index)
return keys return keys
def writefile(module, filename, content): def writefile(module, filename, content):
fd, tmp_path = tempfile.mkstemp('', 'tmp', os.path.dirname(filename)) fd, tmp_path = tempfile.mkstemp('', 'tmp', os.path.dirname(filename))
f = open(tmp_path,"w") f = open(tmp_path, "w")
try: try:
f.write(content) f.write(content)
@ -467,6 +481,7 @@ def writefile(module, filename, content):
f.close() f.close()
module.atomic_move(tmp_path, filename) module.atomic_move(tmp_path, filename)
def serialize(keys): def serialize(keys):
lines = [] lines = []
new_keys = keys.values() new_keys = keys.values()
@ -496,24 +511,26 @@ def serialize(keys):
key_line = key[0] key_line = key[0]
else: else:
key_line = "%s%s %s %s\n" % (option_str, key_type, keyhash, comment) key_line = "%s%s %s %s\n" % (option_str, key_type, keyhash, comment)
except: except Exception:
key_line = key key_line = key
lines.append(key_line) lines.append(key_line)
return ''.join(lines) return ''.join(lines)
def enforce_state(module, params): def enforce_state(module, params):
""" """
Add or remove key. Add or remove key.
""" """
user = params["user"] user = params["user"]
key = params["key"] key = params["key"]
path = params.get("path", None) path = params.get("path", None)
manage_dir = params.get("manage_dir", True) manage_dir = params.get("manage_dir", True)
state = params.get("state", "present") state = params.get("state", "present")
key_options = params.get("key_options", None) key_options = params.get("key_options", None)
exclusive = params.get("exclusive", False) exclusive = params.get("exclusive", False)
error_msg = "Error getting key from: %s" comment = params.get("comment", None)
error_msg = "Error getting key from: %s"
# if the key is a url, request it and use it as key source # if the key is a url, request it and use it as key source
if key.startswith("http"): if key.startswith("http"):
@ -559,6 +576,9 @@ def enforce_state(module, params):
# rank here is the rank in the provided new keys, which may be unrelated to rank in existing_keys # rank here is the rank in the provided new keys, which may be unrelated to rank in existing_keys
parsed_new_key = (parsed_new_key[0], parsed_new_key[1], parsed_options, parsed_new_key[3], parsed_new_key[4]) parsed_new_key = (parsed_new_key[0], parsed_new_key[1], parsed_options, parsed_new_key[3], parsed_new_key[4])
if comment is not None:
parsed_new_key = (parsed_new_key[0], parsed_new_key[1], parsed_new_key[2], comment, parsed_new_key[4])
matched = False matched = False
non_matching_keys = [] non_matching_keys = []
@ -574,7 +594,7 @@ def enforce_state(module, params):
matched = True matched = True
# handle idempotent state=present # handle idempotent state=present
if state=="present": if state == "present":
keys_to_exist.append(parsed_new_key[0]) keys_to_exist.append(parsed_new_key[0])
if len(non_matching_keys) > 0: if len(non_matching_keys) > 0:
for non_matching_key in non_matching_keys: for non_matching_key in non_matching_keys:
@ -590,7 +610,7 @@ def enforce_state(module, params):
existing_keys[parsed_new_key[0]] = (parsed_new_key[0], parsed_new_key[1], parsed_new_key[2], parsed_new_key[3], total_rank) existing_keys[parsed_new_key[0]] = (parsed_new_key[0], parsed_new_key[1], parsed_new_key[2], parsed_new_key[3], total_rank)
do_write = True do_write = True
elif state=="absent": elif state == "absent":
if not matched: if not matched:
continue continue
del existing_keys[parsed_new_key[0]] del existing_keys[parsed_new_key[0]]
@ -607,35 +627,41 @@ def enforce_state(module, params):
if do_write: if do_write:
filename = keyfile(module, user, do_write, path, manage_dir) filename = keyfile(module, user, do_write, path, manage_dir)
new_content = serialize(existing_keys) new_content = serialize(existing_keys)
diff = {
'before_header': params['keyfile'], diff = None
'after_header': filename, if module._diff:
'before': existing_content, diff = {
'after': new_content, 'before_header': params['keyfile'],
} 'after_header': filename,
'before': existing_content,
'after': new_content,
}
params['diff'] = diff
if module.check_mode: if module.check_mode:
module.exit_json(changed=True, diff=diff) module.exit_json(changed=True, diff=diff)
writefile(module, filename, new_content) writefile(module, filename, new_content)
params['changed'] = True params['changed'] = True
params['diff'] = diff
else: else:
if module.check_mode: if module.check_mode:
module.exit_json(changed=False) module.exit_json(changed=False)
return params return params
def main(): def main():
module = AnsibleModule( module = AnsibleModule(
argument_spec = dict( argument_spec=dict(
user = dict(required=True, type='str'), user=dict(required=True, type='str'),
key = dict(required=True, type='str'), key=dict(required=True, type='str'),
path = dict(required=False, type='str'), path=dict(required=False, type='str'),
manage_dir = dict(required=False, type='bool', default=True), manage_dir=dict(required=False, type='bool', default=True),
state = dict(default='present', choices=['absent','present']), state=dict(default='present', choices=['absent', 'present']),
key_options = dict(required=False, type='str'), key_options=dict(required=False, type='str'),
unique = dict(default=False, type='bool'), unique=dict(default=False, type='bool'),
exclusive = dict(default=False, type='bool'), exclusive=dict(default=False, type='bool'),
validate_certs = dict(default=True, type='bool'), comment=dict(required=False, default=None, type='str'),
validate_certs=dict(default=True, type='bool'),
), ),
supports_check_mode=True supports_check_mode=True
) )
@ -643,5 +669,6 @@ def main():
results = enforce_state(module, module.params) results = enforce_state(module, module.params)
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -1,39 +1,35 @@
--- dss_key_basic: ssh-dss DATA_BASIC root@testing
dss_key_basic: > dss_key_unquoted_option: idle-timeout=5m ssh-dss DATA_UNQUOTED_OPTION root@testing
ssh-dss DATA_BASIC root@testing dss_key_command: command="/bin/true" ssh-dss DATA_COMMAND root@testing
dss_key_unquoted_option: > dss_key_complex_command: command="echo foo 'bar baz'" ssh-dss DATA_COMPLEX_COMMAND root@testing
idle-timeout=5m ssh-dss DATA_UNQUOTED_OPTION root@testing dss_key_command_single_option: no-port-forwarding,command="/bin/true" ssh-dss DATA_COMMAND_SINGLE_OPTIONS root@testing
dss_key_command: > dss_key_command_multiple_options: no-port-forwarding,idle-timeout=5m,command="/bin/true" ssh-dss DATA_COMMAND_MULTIPLE_OPTIONS root@testing
command="/bin/true" ssh-dss DATA_COMMAND root@testing dss_key_trailing: ssh-dss DATA_TRAILING root@testing foo bar baz
dss_key_complex_command: > rsa_key_basic: ssh-rsa DATA_BASIC root@testing
command="echo foo 'bar baz'" ssh-dss DATA_COMPLEX_COMMAND root@testing
dss_key_command_single_option: >
no-port-forwarding,command="/bin/true" ssh-dss DATA_COMMAND_SINGLE_OPTIONS root@testing
dss_key_command_multiple_options: >
no-port-forwarding,idle-timeout=5m,command="/bin/true" ssh-dss DATA_COMMAND_MULTIPLE_OPTIONS root@testing
dss_key_trailing: >
ssh-dss DATA_TRAILING root@testing foo bar baz
rsa_key_basic: >
ssh-rsa DATA_BASIC root@testing
multiple_key_base: | multiple_key_base: |
ssh-rsa DATA_BASIC 1@testing ssh-rsa DATA_BASIC 1@testing
ssh-dss DATA_TRAILING 2@testing foo bar baz ssh-dss DATA_TRAILING 2@testing foo bar baz
ssh-dss DATA_TRAILING 3@testing foo bar baz ssh-dss DATA_TRAILING 3@testing foo bar baz
ecdsa-sha2-nistp521 ECDSA_DATA 4@testing ecdsa-sha2-nistp521 ECDSA_DATA 4@testing
multiple_key_different_order: | multiple_key_different_order: |
ssh-dss DATA_TRAILING 2@testing foo bar baz ssh-dss DATA_TRAILING 2@testing foo bar baz
ssh-dss DATA_TRAILING 3@testing foo bar baz ssh-dss DATA_TRAILING 3@testing foo bar baz
ssh-rsa DATA_BASIC 1@testing ssh-rsa DATA_BASIC 1@testing
ecdsa-sha2-nistp521 ECDSA_DATA 4@testing ecdsa-sha2-nistp521 ECDSA_DATA 4@testing
multiple_key_different_order_2: | multiple_key_different_order_2: |
ssh-dss DATA_TRAILING 2@testing foo bar baz ssh-dss DATA_TRAILING 2@testing foo bar baz
ssh-rsa WHATEVER 2.5@testing ssh-rsa WHATEVER 2.5@testing
ssh-dss DATA_TRAILING 3@testing foo bar baz ssh-dss DATA_TRAILING 3@testing foo bar baz
ssh-rsa DATA_BASIC 1@testing ssh-rsa DATA_BASIC 1@testing
ecdsa-sha2-nistp521 ECDSA_DATA 4@testing ecdsa-sha2-nistp521 ECDSA_DATA 4@testing
multiple_key_exclusive: | multiple_key_exclusive: |
ssh-rsa DATA_BASIC 1@testing ssh-rsa DATA_BASIC 1@testing
ecdsa-sha2-nistp521 ECDSA_DATA 4@testing ecdsa-sha2-nistp521 ECDSA_DATA 4@testing
multiple_keys_comments: | multiple_keys_comments: |
ssh-rsa DATA_BASIC 1@testing ssh-rsa DATA_BASIC 1@testing
# I like adding comments yo-dude-this-is-not-a-key INVALID_DATA 2@testing # I like adding comments yo-dude-this-is-not-a-key INVALID_DATA 2@testing

View file

@ -22,52 +22,59 @@
- name: copy an existing file in place with comments - name: copy an existing file in place with comments
copy: src=existing_authorized_keys dest="{{output_dir|expanduser}}/authorized_keys" copy:
src: existing_authorized_keys
dest: "{{ output_dir | expanduser }}/authorized_keys"
- name: add multiple keys different order - name: add multiple keys different order
authorized_key: authorized_key:
user: root user: root
key: "{{ multiple_key_different_order_2 }}" key: "{{ multiple_key_different_order_2 }}"
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- name: get the file content - name: get the file content
shell: cat "{{output_dir|expanduser}}/authorized_keys" shell: cat "{{ output_dir | expanduser }}/authorized_keys"
changed_when: no
register: multiple_keys_existing register: multiple_keys_existing
- name: assert that the key was added and comments and ordering preserved - name: assert that the key was added and comments and ordering preserved
assert: assert:
that: that:
- 'result.changed == True' - 'result.changed == True'
- '"# I like candy" in multiple_keys_existing.stdout' - '"# I like candy" in multiple_keys_existing.stdout'
- '"# I like candy" in multiple_keys_existing.stdout_lines[0]' - '"# I like candy" in multiple_keys_existing.stdout_lines[0]'
- '"ssh-rsa DATA_BASIC 1@testing" in multiple_keys_existing.stdout' - '"ssh-rsa DATA_BASIC 1@testing" in multiple_keys_existing.stdout'
# The specific index is a little fragile, but I want to verify the line shows up # The specific index is a little fragile, but I want to verify the line shows up
# as the 3rd line in the new entries after the existing entries and comments are preserved # as the 3rd line in the new entries after the existing entries and comments are preserved
- '"ssh-rsa DATA_BASIC 1@testing" in multiple_keys_existing.stdout_lines[7]' - '"ssh-rsa DATA_BASIC 1@testing" in multiple_keys_existing.stdout_lines[7]'
# start afresh # start afresh
- name: remove file foo.txt - name: remove file foo.txt
file: path="{{output_dir|expanduser}}/authorized_keys" state=absent file:
path: "{{ output_dir | expanduser }}/authorized_keys"
state: absent
- name: touch the authorized_keys file - name: touch the authorized_keys file
file: dest="{{output_dir}}/authorized_keys" state=touch file:
dest: "{{ output_dir }}/authorized_keys"
state: touch
register: result register: result
- name: assert that the authorized_keys file was created - name: assert that the authorized_keys file was created
assert: assert:
that: that:
- 'result.changed == True' - 'result.changed == True'
- 'result.state == "file"' - 'result.state == "file"'
- name: add multiple keys - name: add multiple keys
authorized_key: authorized_key:
user: root user: root
key: "{{ multiple_key_base }}" key: "{{ multiple_key_base }}"
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- name: assert that the key was added - name: assert that the key was added
@ -82,7 +89,7 @@
user: root user: root
key: "{{ multiple_key_different_order }}" key: "{{ multiple_key_different_order }}"
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- name: assert that the key was added - name: assert that the key was added
@ -97,23 +104,23 @@
user: root user: root
key: "{{ multiple_key_exclusive }}" key: "{{ multiple_key_exclusive }}"
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
exclusive: true exclusive: true
register: result register: result
- name: assert that the key was added - name: assert that the key was added
assert: assert:
that: that:
- 'result.changed == True' - 'result.changed == True'
- 'result.key == multiple_key_exclusive' - 'result.key == multiple_key_exclusive'
- 'result.key_options == None' - 'result.key_options == None'
- name: add multiple keys in different calls - name: add multiple keys in different calls
authorized_key: authorized_key:
user: root user: root
key: "ecdsa-sha2-nistp521 ECDSA_DATA 4@testing" key: "ecdsa-sha2-nistp521 ECDSA_DATA 4@testing"
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- name: add multiple keys in different calls - name: add multiple keys in different calls
@ -121,38 +128,40 @@
user: root user: root
key: "ssh-rsa DATA_BASIC 1@testing" key: "ssh-rsa DATA_BASIC 1@testing"
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- name: get the file content - name: get the file content
shell: cat "{{output_dir|expanduser}}/authorized_keys" shell: cat "{{ output_dir | expanduser }}/authorized_keys"
changed_when: no
register: multiple_keys_at_a_time register: multiple_keys_at_a_time
- name: assert that the key was added - name: assert that the key was added
assert: assert:
that: that:
- 'result.changed == false' - 'result.changed == false'
- 'multiple_keys_at_a_time.stdout == multiple_key_exclusive.strip()' - 'multiple_keys_at_a_time.stdout == multiple_key_exclusive.strip()'
- name: add multiple keys comment - name: add multiple keys comment
authorized_key: authorized_key:
user: root user: root
key: "{{ multiple_keys_comments }}" key: "{{ multiple_keys_comments }}"
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
exclusive: true exclusive: true
register: result register: result
- name: get the file content - name: get the file content
shell: cat "{{output_dir|expanduser}}/authorized_keys" shell: cat "{{ output_dir | expanduser }}/authorized_keys"
changed_when: no
register: multiple_keys_comments register: multiple_keys_comments
- name: assert that the keys exist and comment only lines were not added - name: assert that the keys exist and comment only lines were not added
assert: assert:
that: that:
- 'result.changed == False' - 'result.changed == False'
- 'multiple_keys_comments.stdout == multiple_key_exclusive.strip()' - 'multiple_keys_comments.stdout == multiple_key_exclusive.strip()'
- 'result.key_options == None' - 'result.key_options == None'
@ -160,24 +169,24 @@
# basic ssh-dss key # basic ssh-dss key
- name: add basic ssh-dss key - name: add basic ssh-dss key
authorized_key: user=root key="{{ dss_key_basic }}" state=present path="{{output_dir|expanduser}}/authorized_keys" authorized_key: user=root key="{{ dss_key_basic }}" state=present path="{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- name: assert that the key was added - name: assert that the key was added
assert: assert:
that: that:
- 'result.changed == True' - 'result.changed == True'
- 'result.key == dss_key_basic' - 'result.key == dss_key_basic'
- 'result.key_options == None' - 'result.key_options == None'
- name: re-add basic ssh-dss key - name: re-add basic ssh-dss key
authorized_key: user=root key="{{ dss_key_basic }}" state=present path="{{output_dir|expanduser}}/authorized_keys" authorized_key: user=root key="{{ dss_key_basic }}" state=present path="{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- name: assert that nothing changed - name: assert that nothing changed
assert: assert:
that: that:
- 'result.changed == False' - 'result.changed == False'
# ------------------------------------------------------------- # -------------------------------------------------------------
# ssh-dss key with an unquoted option # ssh-dss key with an unquoted option
@ -187,28 +196,28 @@
user: root user: root
key: "{{ dss_key_unquoted_option }}" key: "{{ dss_key_unquoted_option }}"
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- name: assert that the key was added - name: assert that the key was added
assert: assert:
that: that:
- 'result.changed == True' - 'result.changed == True'
- 'result.key == dss_key_unquoted_option' - 'result.key == dss_key_unquoted_option'
- 'result.key_options == None' - 'result.key_options == None'
- name: re-add ssh-dss key with an unquoted option - name: re-add ssh-dss key with an unquoted option
authorized_key: authorized_key:
user: root user: root
key: "{{ dss_key_unquoted_option }}" key: "{{ dss_key_unquoted_option }}"
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- name: assert that nothing changed - name: assert that nothing changed
assert: assert:
that: that:
- 'result.changed == False' - 'result.changed == False'
# ------------------------------------------------------------- # -------------------------------------------------------------
# ssh-dss key with a leading command="/bin/foo" # ssh-dss key with a leading command="/bin/foo"
@ -218,28 +227,28 @@
user: root user: root
key: "{{ dss_key_command }}" key: "{{ dss_key_command }}"
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- name: assert that the key was added - name: assert that the key was added
assert: assert:
that: that:
- 'result.changed == True' - 'result.changed == True'
- 'result.key == dss_key_command' - 'result.key == dss_key_command'
- 'result.key_options == None' - 'result.key_options == None'
- name: re-add ssh-dss key with a leading command - name: re-add ssh-dss key with a leading command
authorized_key: authorized_key:
user: root user: root
key: "{{ dss_key_command }}" key: "{{ dss_key_command }}"
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- name: assert that nothing changed - name: assert that nothing changed
assert: assert:
that: that:
- 'result.changed == False' - 'result.changed == False'
# ------------------------------------------------------------- # -------------------------------------------------------------
# ssh-dss key with a complex quoted leading command # ssh-dss key with a complex quoted leading command
@ -250,28 +259,28 @@
user: root user: root
key: "{{ dss_key_complex_command }}" key: "{{ dss_key_complex_command }}"
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- name: assert that the key was added - name: assert that the key was added
assert: assert:
that: that:
- 'result.changed == True' - 'result.changed == True'
- 'result.key == dss_key_complex_command' - 'result.key == dss_key_complex_command'
- 'result.key_options == None' - 'result.key_options == None'
- name: re-add ssh-dss key with a complex quoted leading command - name: re-add ssh-dss key with a complex quoted leading command
authorized_key: authorized_key:
user: root user: root
key: "{{ dss_key_complex_command }}" key: "{{ dss_key_complex_command }}"
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- name: assert that nothing changed - name: assert that nothing changed
assert: assert:
that: that:
- 'result.changed == False' - 'result.changed == False'
# ------------------------------------------------------------- # -------------------------------------------------------------
# ssh-dss key with a command and a single option, which are # ssh-dss key with a command and a single option, which are
@ -282,28 +291,28 @@
user: root user: root
key: "{{ dss_key_command_single_option }}" key: "{{ dss_key_command_single_option }}"
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- name: assert that the key was added - name: assert that the key was added
assert: assert:
that: that:
- 'result.changed == True' - 'result.changed == True'
- 'result.key == dss_key_command_single_option' - 'result.key == dss_key_command_single_option'
- 'result.key_options == None' - 'result.key_options == None'
- name: re-add ssh-dss key with a command and a single option - name: re-add ssh-dss key with a command and a single option
authorized_key: authorized_key:
user: root user: root
key: "{{ dss_key_command_single_option }}" key: "{{ dss_key_command_single_option }}"
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- name: assert that nothing changed - name: assert that nothing changed
assert: assert:
that: that:
- 'result.changed == False' - 'result.changed == False'
# ------------------------------------------------------------- # -------------------------------------------------------------
# ssh-dss key with a command and multiple other options # ssh-dss key with a command and multiple other options
@ -313,28 +322,28 @@
user: root user: root
key: "{{ dss_key_command_multiple_options }}" key: "{{ dss_key_command_multiple_options }}"
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- name: assert that the key was added - name: assert that the key was added
assert: assert:
that: that:
- 'result.changed == True' - 'result.changed == True'
- 'result.key == dss_key_command_multiple_options' - 'result.key == dss_key_command_multiple_options'
- 'result.key_options == None' - 'result.key_options == None'
- name: re-add ssh-dss key with a command and multiple options - name: re-add ssh-dss key with a command and multiple options
authorized_key: authorized_key:
user: root user: root
key: "{{ dss_key_command_multiple_options }}" key: "{{ dss_key_command_multiple_options }}"
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- name: assert that nothing changed - name: assert that nothing changed
assert: assert:
that: that:
- 'result.changed == False' - 'result.changed == False'
# ------------------------------------------------------------- # -------------------------------------------------------------
# ssh-dss key with multiple trailing parts, which are space- # ssh-dss key with multiple trailing parts, which are space-
@ -345,28 +354,28 @@
user: root user: root
key: "{{ dss_key_trailing }}" key: "{{ dss_key_trailing }}"
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- name: assert that the key was added - name: assert that the key was added
assert: assert:
that: that:
- 'result.changed == True' - 'result.changed == True'
- 'result.key == dss_key_trailing' - 'result.key == dss_key_trailing'
- 'result.key_options == None' - 'result.key_options == None'
- name: re-add ssh-dss key with trailing parts - name: re-add ssh-dss key with trailing parts
authorized_key: authorized_key:
user: root user: root
key: "{{ dss_key_trailing }}" key: "{{ dss_key_trailing }}"
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- name: assert that nothing changed - name: assert that nothing changed
assert: assert:
that: that:
- 'result.changed == False' - 'result.changed == False'
# ------------------------------------------------------------- # -------------------------------------------------------------
# basic ssh-dss key with mutliple permit-open options # basic ssh-dss key with mutliple permit-open options
@ -378,48 +387,99 @@
key: "{{ dss_key_basic }}" key: "{{ dss_key_basic }}"
key_options: 'no-agent-forwarding,no-X11-forwarding,permitopen="10.9.8.1:8080",permitopen="10.9.8.1:9001"' key_options: 'no-agent-forwarding,no-X11-forwarding,permitopen="10.9.8.1:8080",permitopen="10.9.8.1:9001"'
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- name: assert that the key with multi-opts was added - name: assert that the key with multi-opts was added
assert: assert:
that: that:
- 'result.changed == True' - 'result.changed == True'
- 'result.key == dss_key_basic' - 'result.key == dss_key_basic'
- 'result.key_options == "no-agent-forwarding,no-X11-forwarding,permitopen=\"10.9.8.1:8080\",permitopen=\"10.9.8.1:9001\""' - 'result.key_options == "no-agent-forwarding,no-X11-forwarding,permitopen=\"10.9.8.1:8080\",permitopen=\"10.9.8.1:9001\""'
- name: get the file content - name: get the file content
shell: cat "{{output_dir|expanduser}}/authorized_keys" | fgrep DATA_BASIC shell: cat "{{ output_dir | expanduser }}/authorized_keys" | fgrep DATA_BASIC
changed_when: no
register: content register: content
- name: validate content - name: validate content
assert: assert:
that: that:
- 'content.stdout == "no-agent-forwarding,no-X11-forwarding,permitopen=\"10.9.8.1:8080\",permitopen=\"10.9.8.1:9001\" ssh-dss DATA_BASIC root@testing"' - 'content.stdout == "no-agent-forwarding,no-X11-forwarding,permitopen=\"10.9.8.1:8080\",permitopen=\"10.9.8.1:9001\" ssh-dss DATA_BASIC root@testing"'
# ------------------------------------------------------------- # -------------------------------------------------------------
# check mode # check mode
- name: copy an existing file in place with comments - name: copy an existing file in place with comments
copy: src=existing_authorized_keys dest="{{output_dir|expanduser}}/authorized_keys" copy:
src: existing_authorized_keys
dest: "{{ output_dir | expanduser }}/authorized_keys"
- authorized_key: - authorized_key:
user: root user: root
key: "{{ multiple_key_different_order_2 }}" key: "{{ multiple_key_different_order_2 }}"
state: present state: present
path: "{{output_dir|expanduser}}/authorized_keys" path: "{{ output_dir | expanduser }}/authorized_keys"
check_mode: True check_mode: True
register: result register: result
- name: assert that the key would be added and that the diff is shown
assert:
that:
- 'result.changed'
- '"ssh-rsa WHATEVER 2.5@testing" in result.diff.after'
- name: assert that the file was not changed - name: assert that the file was not changed
copy: src=existing_authorized_keys dest="{{output_dir|expanduser}}/authorized_keys" copy:
src: existing_authorized_keys
dest: "{{ output_dir | expanduser }}/authorized_keys"
register: result register: result
- assert: - assert:
that: that:
- 'result.changed == False' - 'result.changed == False'
# -------------------------------------------------------------
# comments
- name: Add rsa key with existing comment
authorized_key:
user: root
key: "{{ rsa_key_basic }}"
state: present
path: "{{ output_dir | expanduser }}/authorized_keys"
register: result
- name: Change the comment on an existing key
authorized_key:
user: root
key: "{{ rsa_key_basic }}"
comment: user@acme.com
state: present
path: "{{ output_dir | expanduser }}/authorized_keys"
register: result
- name: get the file content
shell: cat "{{ output_dir | expanduser }}/authorized_keys" | fgrep DATA_BASIC
changed_when: no
register: content
- name: Assert that comment on an existing key was changed
assert:
that:
- "'user@acme.com' in content.stdout"
- name: Set the same key with comment to ensure no changes are reported
authorized_key:
user: root
key: "{{ rsa_key_basic }}"
comment: user@acme.com
state: present
path: "{{ output_dir | expanduser }}/authorized_keys"
register: result
- name: Assert that no changes were made when running again
assert:
that:
- not result.changed
- debug:
var: "{{ item }}"
verbosity: 1
with_items:
- result
- content

View file

@ -434,7 +434,6 @@ lib/ansible/modules/storage/zfs/zfs.py
lib/ansible/modules/system/aix_inittab.py lib/ansible/modules/system/aix_inittab.py
lib/ansible/modules/system/alternatives.py lib/ansible/modules/system/alternatives.py
lib/ansible/modules/system/at.py lib/ansible/modules/system/at.py
lib/ansible/modules/system/authorized_key.py
lib/ansible/modules/system/capabilities.py lib/ansible/modules/system/capabilities.py
lib/ansible/modules/system/cron.py lib/ansible/modules/system/cron.py
lib/ansible/modules/system/cronvar.py lib/ansible/modules/system/cronvar.py