- #! /usr/bin/env python3
-
- from datetime import datetime
- import string
- import subprocess
-
- from ansible.module_utils.basic import *
-
- __doc__ = '''
- module: ssh_cert
- author: Edoardo Putti
- short_description: Check ssh certificate validity
- '''
-
- CERT_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S"
-
-
- def serial(lines):
- for l in lines:
- if l.startswith('Serial'):
- return int(l.split().pop(), 10)
-
-
- def signin_ca(lines):
- for l in lines:
- if l.startswith('Signing CA'):
- # return l.split().pop()
- # Starting from OpenSSH v8 the output format of ssh-keygen
- # has changed, this should work for all versions:
- return l.split()[3]
-
-
-
- def still_valid(cert_timestamps):
- t = datetime.datetime.today()
- return t < cert_timestamps['valid']['to'] and t > cert_timestamps['valid']['from']
-
-
- def expired(cert_timestamps):
- t = datetime.datetime.today()
- return t > cert_timestamps['valid']['to']
-
-
- def not_valid(cert_timestamps):
- t = datetime.datetime.today()
- return t < cert_timestamps['valid']['from']
-
-
- def cert_type(lines):
- for l in lines:
- if l.startswith('Type'):
- return l.split(maxsplit=2)[1:]
-
-
- def valid_from(lines):
- for l in lines:
- if l.startswith('Valid'):
- return datetime.datetime.strptime(l.split()[2], CERT_TIME_FORMAT)
-
-
- def valid_to(lines):
- for l in lines:
- if l.startswith('Valid'):
- return datetime.datetime.strptime(l.split()[4], CERT_TIME_FORMAT)
-
-
- def main():
- module = AnsibleModule(
- argument_spec=dict(),
- supports_check_mode=False,
- )
- result = {}
- result['rc'] = 0
- result['failed'] = False
- result['ca'] = {}
- result['ca']['path'] = '/etc/ssh/user_ca.pub'
- result['certificate'] = {}
- result['certificate']['path'] = '/etc/ssh/ssh_host_ed25519_key-cert.pub'
-
- ca_output = subprocess.check_output([
- 'ssh-keygen',
- '-l',
- '-f', result['ca']['path'],
- ])
-
- # If multiple CA are present verify cert against the first one
- ca_output = ca_output.splitlines()[0]
- ca_lines = ca_output.decode().split(maxsplit=2)
- result['ca']['fingerprint'] = ca_lines[1]
- result['ca']['comment'] = ca_lines[2]
-
- cert_output = subprocess.check_output([
- 'ssh-keygen',
- '-L',
- '-f', result['certificate']['path'],
- ])
- cert_lines = [line.strip() for line in cert_output.decode().split('\n')]
-
- result['certificate']['signin_ca'] = signin_ca(cert_lines)
- result['certificate']['valid'] = {
- 'from': valid_from(cert_lines),
- 'to': valid_to(cert_lines),
- }
-
- if not still_valid(result['certificate']):
- result['failed'] = True
- result['msg'] = 'The certificate is not valid now'
- if not_valid(result['certificate']):
- result['rc'] = 2
- if expired(result['certificate']):
- result['rc'] = 3
-
- result['certificate']['serial'] = serial(cert_lines)
- result['certificate']['type'] = cert_type(cert_lines)
-
- if not result['certificate']['signin_ca'] == result['ca']['fingerprint']:
- result['failed'] = True
- result['msg'] = 'The provided CA did not sign the certificate specified'
- result['rc'] = 1
-
- module.exit_json(**result)
-
-
- if __name__ == '__main__':
- main()
|