mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Merge pull request #40543 from rallytime/fix-40005
Add the "fingerprint_hash_type" option to ssh state and module
This commit is contained in:
commit
cb9dcb1e1b
2 changed files with 117 additions and 24 deletions
|
@ -221,7 +221,7 @@ def _validate_keys(key_file):
|
|||
return ret
|
||||
|
||||
|
||||
def _fingerprint(public_key):
|
||||
def _fingerprint(public_key, fingerprint_hash_type=None):
|
||||
'''
|
||||
Return a public key fingerprint based on its base64-encoded representation
|
||||
|
||||
|
@ -229,7 +229,39 @@ def _fingerprint(public_key):
|
|||
in the form "xx:xx:...:xx"
|
||||
|
||||
If the key is invalid (incorrect base64 string), return None
|
||||
|
||||
public_key
|
||||
The public key to return the fingerprint for
|
||||
|
||||
fingerprint_hash_type
|
||||
The public key fingerprint hash type that the public key fingerprint
|
||||
was originally hashed with. This defaults to ``md5`` if not specified.
|
||||
|
||||
.. versionadded:: 2016.11.4
|
||||
|
||||
.. note::
|
||||
|
||||
The default value of the ``fingerprint_hash_type`` will change to
|
||||
``sha256`` in Salt Nitrogen.
|
||||
|
||||
'''
|
||||
if fingerprint_hash_type:
|
||||
hash_type = fingerprint_hash_type.lower()
|
||||
else:
|
||||
# Set fingerprint_hash_type to md5 as default
|
||||
log.warning('Public Key hashing currently defaults to "md5". This will '
|
||||
'change to "sha256" in the Nitrogen release.')
|
||||
hash_type = 'md5'
|
||||
|
||||
try:
|
||||
hash_func = getattr(hashlib, hash_type)
|
||||
except AttributeError:
|
||||
raise CommandExecutionError(
|
||||
'The fingerprint_hash_type {0} is not supported.'.format(
|
||||
hash_type
|
||||
)
|
||||
)
|
||||
|
||||
try:
|
||||
if six.PY2:
|
||||
raw_key = public_key.decode('base64')
|
||||
|
@ -237,7 +269,9 @@ def _fingerprint(public_key):
|
|||
raw_key = base64.b64decode(public_key, validate=True) # pylint: disable=E1123
|
||||
except binascii.Error:
|
||||
return None
|
||||
ret = hashlib.md5(raw_key).hexdigest()
|
||||
|
||||
ret = hash_func(raw_key).hexdigest()
|
||||
|
||||
chunks = [ret[i:i + 2] for i in range(0, len(ret), 2)]
|
||||
return ':'.join(chunks)
|
||||
|
||||
|
@ -703,7 +737,7 @@ def set_auth_key(
|
|||
return 'new'
|
||||
|
||||
|
||||
def _parse_openssh_output(lines):
|
||||
def _parse_openssh_output(lines, fingerprint_hash_type=None):
|
||||
'''
|
||||
Helper function which parses ssh-keygen -F and ssh-keyscan function output
|
||||
and yield dict with keys information, one by one.
|
||||
|
@ -715,7 +749,8 @@ def _parse_openssh_output(lines):
|
|||
hostname, enc, key = line.split()
|
||||
except ValueError: # incorrect format
|
||||
continue
|
||||
fingerprint = _fingerprint(key)
|
||||
fingerprint = _fingerprint(key,
|
||||
fingerprint_hash_type=fingerprint_hash_type)
|
||||
if not fingerprint:
|
||||
continue
|
||||
yield {'hostname': hostname, 'key': key, 'enc': enc,
|
||||
|
@ -723,7 +758,11 @@ def _parse_openssh_output(lines):
|
|||
|
||||
|
||||
@decorators.which('ssh-keygen')
|
||||
def get_known_host(user, hostname, config=None, port=None):
|
||||
def get_known_host(user,
|
||||
hostname,
|
||||
config=None,
|
||||
port=None,
|
||||
fingerprint_hash_type=None):
|
||||
'''
|
||||
Return information about known host from the configfile, if any.
|
||||
If there is no such key, return None.
|
||||
|
@ -744,7 +783,10 @@ def get_known_host(user, hostname, config=None, port=None):
|
|||
lines = __salt__['cmd.run'](cmd,
|
||||
ignore_retcode=True,
|
||||
python_shell=False).splitlines()
|
||||
known_hosts = list(_parse_openssh_output(lines))
|
||||
known_hosts = list(
|
||||
_parse_openssh_output(lines,
|
||||
fingerprint_hash_type=fingerprint_hash_type)
|
||||
)
|
||||
return known_hosts[0] if known_hosts else None
|
||||
|
||||
|
||||
|
@ -753,7 +795,8 @@ def recv_known_host(hostname,
|
|||
enc=None,
|
||||
port=None,
|
||||
hash_known_hosts=True,
|
||||
timeout=5):
|
||||
timeout=5,
|
||||
fingerprint_hash_type=None):
|
||||
'''
|
||||
Retrieve information about host public key from remote server
|
||||
|
||||
|
@ -780,6 +823,17 @@ def recv_known_host(hostname,
|
|||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
fingerprint_hash_type
|
||||
The public key fingerprint hash type that the public key fingerprint
|
||||
was originally hashed with. This defaults to ``md5`` if not specified.
|
||||
|
||||
.. versionadded:: 2016.11.4
|
||||
|
||||
.. note::
|
||||
|
||||
The default value of the ``fingerprint_hash_type`` will change to
|
||||
``sha256`` in Salt Nitrogen.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
@ -806,12 +860,13 @@ def recv_known_host(hostname,
|
|||
while not lines and attempts > 0:
|
||||
attempts = attempts - 1
|
||||
lines = __salt__['cmd.run'](cmd, python_shell=False).splitlines()
|
||||
known_hosts = list(_parse_openssh_output(lines))
|
||||
known_hosts = list(_parse_openssh_output(lines,
|
||||
fingerprint_hash_type=fingerprint_hash_type))
|
||||
return known_hosts[0] if known_hosts else None
|
||||
|
||||
|
||||
def check_known_host(user=None, hostname=None, key=None, fingerprint=None,
|
||||
config=None, port=None):
|
||||
config=None, port=None, fingerprint_hash_type=None):
|
||||
'''
|
||||
Check the record in known_hosts file, either by its value or by fingerprint
|
||||
(it's enough to set up either key or fingerprint, you don't need to set up
|
||||
|
@ -838,7 +893,11 @@ def check_known_host(user=None, hostname=None, key=None, fingerprint=None,
|
|||
else:
|
||||
config = config or '.ssh/known_hosts'
|
||||
|
||||
known_host = get_known_host(user, hostname, config=config, port=port)
|
||||
known_host = get_known_host(user,
|
||||
hostname,
|
||||
config=config,
|
||||
port=port,
|
||||
fingerprint_hash_type=fingerprint_hash_type)
|
||||
|
||||
if not known_host or 'fingerprint' not in known_host:
|
||||
return 'add'
|
||||
|
@ -892,7 +951,8 @@ def set_known_host(user=None,
|
|||
enc=None,
|
||||
config=None,
|
||||
hash_known_hosts=True,
|
||||
timeout=5):
|
||||
timeout=5,
|
||||
fingerprint_hash_type=None):
|
||||
'''
|
||||
Download SSH public key from remote host "hostname", optionally validate
|
||||
its fingerprint against "fingerprint" variable and save the record in the
|
||||
|
@ -907,7 +967,7 @@ def set_known_host(user=None,
|
|||
The name of the remote host (e.g. "github.com")
|
||||
|
||||
fingerprint
|
||||
The fingerprint of the key which must be presented in the known_hosts
|
||||
The fingerprint of the key which must be present in the known_hosts
|
||||
file (optional if key specified)
|
||||
|
||||
key
|
||||
|
@ -940,6 +1000,17 @@ def set_known_host(user=None,
|
|||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
fingerprint_hash_type
|
||||
The public key fingerprint hash type that the public key fingerprint
|
||||
was originally hashed with. This defaults to ``md5`` if not specified.
|
||||
|
||||
.. versionadded:: 2016.11.4
|
||||
|
||||
.. note::
|
||||
|
||||
The default value of the ``fingerprint_hash_type`` will change to
|
||||
``sha256`` in Salt Nitrogen.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
@ -957,7 +1028,11 @@ def set_known_host(user=None,
|
|||
|
||||
update_required = False
|
||||
check_required = False
|
||||
stored_host = get_known_host(user, hostname, config, port)
|
||||
stored_host = get_known_host(user,
|
||||
hostname,
|
||||
config=config,
|
||||
port=port,
|
||||
fingerprint_hash_type=fingerprint_hash_type)
|
||||
|
||||
if not stored_host:
|
||||
update_required = True
|
||||
|
@ -976,7 +1051,8 @@ def set_known_host(user=None,
|
|||
enc=enc,
|
||||
port=port,
|
||||
hash_known_hosts=hash_known_hosts,
|
||||
timeout=timeout)
|
||||
timeout=timeout,
|
||||
fingerprint_hash_type=fingerprint_hash_type)
|
||||
if not remote_host:
|
||||
return {'status': 'error',
|
||||
'error': 'Unable to receive remote host key'}
|
||||
|
|
|
@ -50,7 +50,8 @@ def present(
|
|||
enc=None,
|
||||
config=None,
|
||||
hash_known_hosts=True,
|
||||
timeout=5):
|
||||
timeout=5,
|
||||
fingerprint_hash_type=None):
|
||||
'''
|
||||
Verifies that the specified host is known by the specified user
|
||||
|
||||
|
@ -96,6 +97,18 @@ def present(
|
|||
and the host in question considered unavailable. Default is 5 seconds.
|
||||
|
||||
.. versionadded:: 2016.3.0
|
||||
|
||||
fingerprint_hash_type
|
||||
The public key fingerprint hash type that the public key fingerprint
|
||||
was originally hashed with. This defaults to ``md5`` if not specified.
|
||||
|
||||
.. versionadded:: 2016.11.4
|
||||
|
||||
.. note::
|
||||
|
||||
The default value of the ``fingerprint_hash_type`` will change to
|
||||
``sha256`` in Salt Nitrogen.
|
||||
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'changes': {},
|
||||
|
@ -127,7 +140,8 @@ def present(
|
|||
key=key,
|
||||
fingerprint=fingerprint,
|
||||
config=config,
|
||||
port=port)
|
||||
port=port,
|
||||
fingerprint_hash_type=fingerprint_hash_type)
|
||||
except CommandNotFoundError as err:
|
||||
ret['result'] = False
|
||||
ret['comment'] = 'ssh.check_known_host error: {0}'.format(err)
|
||||
|
@ -146,14 +160,17 @@ def present(
|
|||
config)
|
||||
return dict(ret, comment=comment)
|
||||
|
||||
result = __salt__['ssh.set_known_host'](user=user, hostname=name,
|
||||
fingerprint=fingerprint,
|
||||
key=key,
|
||||
port=port,
|
||||
enc=enc,
|
||||
config=config,
|
||||
hash_known_hosts=hash_known_hosts,
|
||||
timeout=timeout)
|
||||
result = __salt__['ssh.set_known_host'](
|
||||
user=user,
|
||||
hostname=name,
|
||||
fingerprint=fingerprint,
|
||||
key=key,
|
||||
port=port,
|
||||
enc=enc,
|
||||
config=config,
|
||||
hash_known_hosts=hash_known_hosts,
|
||||
timeout=timeout,
|
||||
fingerprint_hash_type=fingerprint_hash_type)
|
||||
if result['status'] == 'exists':
|
||||
return dict(ret,
|
||||
comment='{0} already exists in {1}'.format(name, config))
|
||||
|
|
Loading…
Add table
Reference in a new issue