oc_adm_ca_server_cert.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. # pylint: skip-file
  2. # flake8: noqa
  3. class CAServerCertConfig(OpenShiftCLIConfig):
  4. ''' CAServerCertConfig is a DTO for the oc adm ca command '''
  5. def __init__(self, kubeconfig, verbose, ca_options):
  6. super(CAServerCertConfig, self).__init__('ca', None, kubeconfig, ca_options)
  7. self.kubeconfig = kubeconfig
  8. self.verbose = verbose
  9. self._ca = ca_options
  10. class CAServerCert(OpenShiftCLI):
  11. ''' Class to wrap the oc adm ca create-server-cert command line'''
  12. def __init__(self,
  13. config,
  14. verbose=False):
  15. ''' Constructor for oadm ca '''
  16. super(CAServerCert, self).__init__(None, config.kubeconfig, verbose)
  17. self.config = config
  18. self.verbose = verbose
  19. def get(self):
  20. '''get the current cert file
  21. If a file exists by the same name in the specified location then the cert exists
  22. '''
  23. cert = self.config.config_options['cert']['value']
  24. if cert and os.path.exists(cert):
  25. return open(cert).read()
  26. return None
  27. def create(self):
  28. '''run openshift oc adm ca create-server-cert cmd'''
  29. # Added this here as a safegaurd for stomping on the
  30. # cert and key files if they exist
  31. if self.config.config_options['backup']['value']:
  32. import time
  33. ext = time.strftime("%Y-%m-%d@%H:%M:%S", time.localtime(time.time()))
  34. date_str = "%s_" + "%s" % ext
  35. if os.path.exists(self.config.config_options['key']['value']):
  36. shutil.copy(self.config.config_options['key']['value'],
  37. date_str % self.config.config_options['key']['value'])
  38. if os.path.exists(self.config.config_options['cert']['value']):
  39. shutil.copy(self.config.config_options['cert']['value'],
  40. date_str % self.config.config_options['cert']['value'])
  41. options = self.config.to_option_list()
  42. cmd = ['ca', 'create-server-cert']
  43. cmd.extend(options)
  44. return self.openshift_cmd(cmd, oadm=True)
  45. def exists(self):
  46. ''' check whether the certificate exists and has the clusterIP '''
  47. cert_path = self.config.config_options['cert']['value']
  48. if not os.path.exists(cert_path):
  49. return False
  50. # Would prefer pyopenssl but is not installed.
  51. # When we verify it is, switch this code
  52. # Here is the code to get the subject and the SAN
  53. # openssl x509 -text -noout -certopt \
  54. # no_header,no_version,no_serial,no_signame,no_validity,no_issuer,no_pubkey,no_sigdump,no_aux \
  55. # -in /etc/origin/master/registry.crt
  56. # Instead of this solution we will use a regex.
  57. cert_names = []
  58. hostnames = self.config.config_options['hostnames']['value'].split(',')
  59. proc = subprocess.Popen(['openssl', 'x509', '-noout', '-text', '-in', cert_path],
  60. stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  61. x509output, _ = proc.communicate()
  62. if proc.returncode == 0:
  63. regex = re.compile(r"^\s*X509v3 Subject Alternative Name:\s*?\n\s*(.*)\s*\n", re.MULTILINE)
  64. match = regex.search(x509output.decode()) # E501
  65. if not match:
  66. return False
  67. for entry in re.split(r", *", match.group(1)):
  68. if entry.startswith('DNS') or entry.startswith('IP Address'):
  69. cert_names.append(entry.split(':')[1])
  70. # now that we have cert names let's compare
  71. cert_set = set(cert_names)
  72. hname_set = set(hostnames)
  73. if cert_set.issubset(hname_set) and hname_set.issubset(cert_set):
  74. return True
  75. return False
  76. @staticmethod
  77. def run_ansible(params, check_mode):
  78. '''run the idempotent ansible code'''
  79. # Filter non-strings from hostnames list s.t. the omit filter
  80. # may be used to conditionally add a hostname.
  81. params['hostnames'] = [host for host in params['hostnames'] if isinstance(host, string_types)]
  82. config = CAServerCertConfig(params['kubeconfig'],
  83. params['debug'],
  84. {'cert': {'value': params['cert'], 'include': True},
  85. 'hostnames': {'value': ','.join(params['hostnames']), 'include': True},
  86. 'overwrite': {'value': True, 'include': True},
  87. 'key': {'value': params['key'], 'include': True},
  88. 'signer_cert': {'value': params['signer_cert'], 'include': True},
  89. 'signer_key': {'value': params['signer_key'], 'include': True},
  90. 'signer_serial': {'value': params['signer_serial'], 'include': True},
  91. 'expire_days': {'value': params['expire_days'], 'include': True},
  92. 'backup': {'value': params['backup'], 'include': False},
  93. })
  94. server_cert = CAServerCert(config)
  95. state = params['state']
  96. if state == 'present':
  97. ########
  98. # Create
  99. ########
  100. if not server_cert.exists() or params['force']:
  101. if check_mode:
  102. return {'changed': True,
  103. 'msg': "CHECK_MODE: Would have created the certificate.",
  104. 'state': state}
  105. api_rval = server_cert.create()
  106. if api_rval['returncode'] != 0:
  107. return {'failed': True, 'msg': api_rval}
  108. return {'changed': True, 'results': api_rval, 'state': state}
  109. ########
  110. # Exists
  111. ########
  112. api_rval = server_cert.get()
  113. return {'changed': False, 'results': api_rval, 'state': state}
  114. return {'failed': True,
  115. 'msg': 'Unknown state passed. %s' % state}