Playbooks to a new Lilik
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 lines
3.2 KiB

  1. #! /usr/bin/env python
  2. from datetime import datetime
  3. import string
  4. import subprocess
  5. from ansible.module_utils.basic import *
  6. __doc__ = '''
  7. module: ssh_cert
  8. author: Edoardo Putti
  9. short_description: Check ssh certificate validity
  10. '''
  11. CERT_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S"
  12. def serial(lines):
  13. for l in lines:
  14. if l.startswith('Serial'):
  15. return int(l.split().pop(), 10)
  16. def signin_ca(lines):
  17. for l in lines:
  18. if l.startswith('Signing CA'):
  19. return l.split().pop()
  20. def still_valid(cert_timestamps):
  21. t = datetime.datetime.today()
  22. return t < cert_timestamps['valid']['to'] and t > cert_timestamps['valid']['from']
  23. def expired(cert_timestamps):
  24. t = datetime.datetime.today()
  25. return t > cert_timestamps['valid']['to']
  26. def not_valid(cert_timestamps):
  27. t = datetime.datetime.today()
  28. return t < cert_timestamps['valid']['from']
  29. def cert_type(lines):
  30. for l in lines:
  31. if l.startswith('Type'):
  32. return string.split(l, maxsplit=2)[1:]
  33. def valid_from(lines):
  34. for l in lines:
  35. if l.startswith('Valid'):
  36. return datetime.datetime.strptime(l.split()[2], CERT_TIME_FORMAT)
  37. def valid_to(lines):
  38. for l in lines:
  39. if l.startswith('Valid'):
  40. return datetime.datetime.strptime(l.split()[4], CERT_TIME_FORMAT)
  41. def main():
  42. module = AnsibleModule(
  43. argument_spec=dict(),
  44. supports_check_mode=False,
  45. )
  46. result = {}
  47. result['rc'] = 0
  48. result['failed'] = False
  49. result['ca'] = {}
  50. result['ca']['path'] = '/etc/ssh/user_ca.pub'
  51. result['certificate'] = {}
  52. result['certificate']['path'] = '/etc/ssh/ssh_host_ed25519_key-cert.pub'
  53. ca_output = subprocess.check_output([
  54. 'ssh-keygen',
  55. '-l',
  56. '-f', result['ca']['path'],
  57. ])
  58. ca_lines = string.split(ca_output, maxsplit=2)
  59. result['ca']['fingerprint'] = ca_lines[1]
  60. result['ca']['comment'] = ca_lines[2]
  61. cert_output = subprocess.check_output([
  62. 'ssh-keygen',
  63. '-L',
  64. '-f', result['certificate']['path'],
  65. ])
  66. cert_lines = [line.strip() for line in cert_output.split('\n')]
  67. result['certificate']['signin_ca'] = signin_ca(cert_lines)
  68. result['certificate']['valid'] = {
  69. 'from': valid_from(cert_lines),
  70. 'to': valid_to(cert_lines),
  71. }
  72. if not still_valid(result['certificate']):
  73. result['failed'] = True
  74. result['msg'] = 'The certificate is not valid now'
  75. if not_valid(result['certificate']):
  76. result['rc'] = 2
  77. if expired(result['certificate']):
  78. result['rc'] = 3
  79. result['certificate']['serial'] = serial(cert_lines)
  80. result['certificate']['type'] = cert_type(cert_lines)
  81. if not result['certificate']['signin_ca'] == result['ca']['fingerprint']:
  82. result['failed'] = True
  83. result['msg'] = 'The provided CA did not sign the certificate specified'
  84. result['rc'] = 1
  85. module.exit_json(**result)
  86. if __name__ == '__main__':
  87. main()