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.

118 lines
3.1 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['ca'] = {}
  49. result['ca']['path'] = '/etc/ssh/user_ca.pub'
  50. result['certificate'] = {}
  51. result['certificate']['path'] = '/etc/ssh/ssh_host_ed25519_key-cert.pub'
  52. ca_output = subprocess.check_output([
  53. 'ssh-keygen',
  54. '-l',
  55. '-f', result['ca']['path'],
  56. ])
  57. ca_lines = string.split(ca_output, maxsplit=2)
  58. result['ca']['fingerprint'] = ca_lines[1]
  59. result['ca']['comment'] = ca_lines[2]
  60. cert_output = subprocess.check_output([
  61. 'ssh-keygen',
  62. '-L',
  63. '-f', result['certificate']['path'],
  64. ])
  65. cert_lines = [line.strip() for line in cert_output.split('\n')]
  66. result['certificate']['signin_ca'] = signin_ca(cert_lines)
  67. result['certificate']['valid'] = {
  68. 'from': valid_from(cert_lines),
  69. 'to': valid_to(cert_lines),
  70. }
  71. if not still_valid(result['certificate']):
  72. result['failed'] = True
  73. result['msg'] = 'The certificate is not valid now'
  74. if not_valid(result['certificate']):
  75. result['rc'] = 2
  76. if expired(result['certificate']):
  77. result['rc'] = 3
  78. result['certificate']['serial'] = serial(cert_lines)
  79. result['certificate']['type'] = cert_type(cert_lines)
  80. if not result['certificate']['signin_ca'] == result['ca']['fingerprint']:
  81. result['failed'] = True
  82. result['msg'] = 'The provided CA did not sign the certificate specified'
  83. result['rc'] = 1
  84. module.exit_json(**result)
  85. if __name__ == '__main__':
  86. main()