openssh_keypair - Add public key and key comment validation (#57993)

- Split the key validation to separate private and public.
- In case public key does not exist, recreate it.
- Validate comment of the key.
- In case comment changed, update the private and public keys.
pull/60377/head
Maxim Babushkin 5 years ago committed by ansibot
parent a3d55a5ddb
commit 27e414200f

@ -0,0 +1,2 @@
bugfixes:
- openssh_keypair - add public key and key comment validation on change

@ -165,7 +165,7 @@ class Keypair(object):
def generate(self, module):
# generate a keypair
if not self.isValid(module, perms_required=False) or self.force:
if not self.isPrivateKeyValid(module, perms_required=False) or self.force:
args = [
module.get_bin_path('ssh-keygen', True),
'-q',
@ -196,11 +196,36 @@ class Keypair(object):
self.remove()
module.fail_json(msg="%s" % to_native(e))
elif not self.isPublicKeyValid(module):
pubkey = module.run_command([module.get_bin_path('ssh-keygen', True), '-yf', self.path])
pubkey = pubkey[1].strip('\n')
try:
self.changed = True
with open(self.path + ".pub", "w") as pubkey_f:
pubkey_f.write(pubkey + '\n')
os.chmod(self.path + ".pub", stat.S_IWUSR + stat.S_IRUSR + stat.S_IRGRP + stat.S_IROTH)
except IOError:
module.fail_json(
msg='The public key is missing or does not match the private key. '
'Unable to regenerate the public key.')
self.public_key = pubkey
if self.comment:
try:
if os.path.exists(self.path) and not os.access(self.path, os.W_OK):
os.chmod(self.path, stat.S_IWUSR + stat.S_IRUSR)
args = [module.get_bin_path('ssh-keygen', True),
'-q', '-o', '-c', '-C', self.comment, '-f', self.path]
module.run_command(args)
except IOError:
module.fail_json(
msg='Unable to update the comment for the public key.')
file_args = module.load_file_common_arguments(module.params)
if module.set_fs_attributes_if_different(file_args, False):
self.changed = True
def isValid(self, module, perms_required=True):
def isPrivateKeyValid(self, module, perms_required=True):
# check if the key is correct
def _check_state():
@ -215,8 +240,6 @@ class Keypair(object):
return False
fingerprint = proc[1].split()
pubkey = module.run_command([module.get_bin_path('ssh-keygen', True), '-yf', self.path])
pubkey = pubkey[1].strip('\n')
keysize = int(fingerprint[0])
keytype = fingerprint[-1][1:-1].lower()
else:
@ -233,13 +256,51 @@ class Keypair(object):
return self.size == keysize
self.fingerprint = fingerprint
self.public_key = pubkey
if not perms_required:
return _check_state() and _check_type() and _check_size()
return _check_state() and _check_perms(module) and _check_type() and _check_size()
def isPublicKeyValid(self, module):
def _get_pubkey_content():
if os.path.exists(self.path + ".pub"):
with open(self.path + ".pub", "r") as pubkey_f:
present_pubkey = pubkey_f.read().strip(' \n')
return present_pubkey
else:
return False
def _parse_pubkey():
pubkey_content = _get_pubkey_content()
if pubkey_content:
parts = pubkey_content.split(' ', 2)
return parts[0], parts[1], '' if len(parts) <= 2 else parts[2]
return False
def _pubkey_valid(pubkey):
if pubkey_parts:
current_pubkey = ' '.join([pubkey_parts[0], pubkey_parts[1]])
return current_pubkey == pubkey
return False
def _comment_valid():
if pubkey_parts:
return pubkey_parts[2] == self.comment
return False
pubkey = module.run_command([module.get_bin_path('ssh-keygen', True), '-yf', self.path])
pubkey = pubkey[1].strip('\n')
pubkey_parts = _parse_pubkey()
if _pubkey_valid(pubkey):
self.public_key = pubkey
if not self.comment:
return _pubkey_valid(pubkey)
return _pubkey_valid(pubkey) and _comment_valid()
def dump(self):
# return result as a dict
@ -309,7 +370,7 @@ def main():
if module.check_mode:
result = keypair.dump()
result['changed'] = module.params['force'] or not keypair.isValid(module)
result['changed'] = module.params['force'] or not keypair.isPrivateKeyValid(module) or not keypair.isPublicKeyValid(module)
module.exit_json(**result)
try:

@ -67,4 +67,16 @@
force: yes
register: output_read_only
- name: Generate privatekey7 - standard with comment
openssh_keypair:
path: '{{ output_dir }}/privatekey7'
comment: 'test@privatekey7'
register: privatekey7_result
- name: Modify privatekey7 comment
openssh_keypair:
path: '{{ output_dir }}/privatekey7'
comment: 'test_modified@privatekey7'
register: privatekey7_modified_result
- import_tasks: ../tests/validate.yml

@ -91,3 +91,9 @@
assert:
that:
- output_read_only is changed
- name: Validate privatekey7 (assert - Public key remains the same after comment change)
assert:
that:
- privatekey7_result.public_key == privatekey7_modified_result.public_key

Loading…
Cancel
Save