Saltstack Official OpenSSH Formula
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

115 lines
3.3KB

  1. #!py
  2. import logging
  3. import os.path
  4. import re
  5. import subprocess
  6. cache = {}
  7. ssh_key_pattern = re.compile("^[^ ]+ (ssh-.+)$")
  8. log = logging.getLogger(__name__)
  9. def config_dir():
  10. if '__master_opts__' in __opts__:
  11. # run started via salt-ssh
  12. return __opts__['__master_opts__']['config_dir']
  13. else:
  14. # run started via salt
  15. return __opts__['config_dir']
  16. def cache_dir():
  17. if '__master_opts__' in __opts__:
  18. # run started via salt-ssh
  19. return __opts__['__master_opts__']['cachedir']
  20. else:
  21. # run started via salt
  22. return __opts__['cachedir']+'/../master'
  23. def minions():
  24. if not 'minions' in cache:
  25. cache['minions'] = __salt__.slsutil.renderer(config_dir() + '/roster')
  26. return cache['minions']
  27. def host_variants(minion):
  28. _variants = [minion]
  29. def add_port_variant(host):
  30. if 'port' in minions()[minion]:
  31. _variants.append("[{}]:{}".format(host, minions()[minion]['port']))
  32. add_port_variant(minion)
  33. if 'host' in minions()[minion]:
  34. host = minions()[minion]['host']
  35. _variants.append(host)
  36. add_port_variant(host)
  37. return _variants
  38. def host_keys_from_known_hosts(minion, path):
  39. '''
  40. Fetches all host keys of the given minion.
  41. '''
  42. if not os.path.isfile(path):
  43. return []
  44. pubkeys = []
  45. def fill_pubkeys(host):
  46. for line in host_key_of(host, path).splitlines():
  47. match = ssh_key_pattern.search(line)
  48. if match:
  49. pubkeys.append(match.group(1))
  50. # Try the minion ID and its variants first
  51. for host in host_variants(minion):
  52. fill_pubkeys(host)
  53. # When no keys were found ...
  54. if not pubkeys:
  55. # ... fetch IP addresses via DNS and try them.
  56. for host in (salt['dig.A'](minion) + salt['dig.AAAA'](minion)):
  57. fill_pubkeys(host)
  58. # When not a single key was found anywhere:
  59. if not pubkeys:
  60. log.error("No SSH host key found for {}. "
  61. "You may need to add it to {}.".format(minion, path))
  62. return "\n".join(pubkeys)
  63. def host_key_of(host, path):
  64. cmd = ["ssh-keygen", "-H", "-F", host, "-f", path]
  65. call = subprocess.Popen(
  66. cmd,
  67. stdout=subprocess.PIPE,
  68. stderr=subprocess.PIPE
  69. )
  70. out, err = call.communicate()
  71. if err == '':
  72. return out
  73. else:
  74. log.error("{} failed:\nSTDERR: {}\nSTDOUT: {}".format(
  75. " ".join(cmd),
  76. err,
  77. out
  78. ))
  79. return ""
  80. def host_keys(minion_id):
  81. # Get keys from trusted known_hosts file
  82. trusted_keys = host_keys_from_known_hosts(minion_id,
  83. config_dir()+'/known_hosts')
  84. if trusted_keys:
  85. return trusted_keys
  86. # Get keys from host key cache
  87. cache_file = "{}/known_hosts_salt_ssh/{}.pub".format(cache_dir(), minion_id)
  88. try:
  89. with open(cache_file, 'r') as f:
  90. return f.read()
  91. except IOError:
  92. return ''
  93. def run():
  94. cache = {} # clear the cache
  95. config = {
  96. 'public_ssh_host_keys': {},
  97. 'public_ssh_host_names': {}
  98. }
  99. for minion in minions().keys():
  100. config['public_ssh_host_keys'][minion] = host_keys(minion)
  101. config['public_ssh_host_names'][minion] = minion
  102. return {'openssh': {'known_hosts': {'salt_ssh': config}}}
  103. # vim: ts=4:sw=4:syntax=python