diff options
Diffstat (limited to 'roles/lib_openshift/src')
-rw-r--r-- | roles/lib_openshift/src/ansible/oc_adm_ca_server_cert.py | 35 | ||||
-rw-r--r-- | roles/lib_openshift/src/class/oc_adm_ca_server_cert.py | 135 | ||||
-rw-r--r-- | roles/lib_openshift/src/doc/ca_server_cert | 96 | ||||
-rw-r--r-- | roles/lib_openshift/src/sources.yml | 10 |
4 files changed, 276 insertions, 0 deletions
diff --git a/roles/lib_openshift/src/ansible/oc_adm_ca_server_cert.py b/roles/lib_openshift/src/ansible/oc_adm_ca_server_cert.py new file mode 100644 index 000000000..c80c2eb44 --- /dev/null +++ b/roles/lib_openshift/src/ansible/oc_adm_ca_server_cert.py @@ -0,0 +1,35 @@ +# pylint: skip-file +# flake8: noqa + +def main(): + ''' + ansible oc adm module for ca create-server-cert + ''' + + module = AnsibleModule( + argument_spec=dict( + state=dict(default='present', type='str', choices=['present']), + debug=dict(default=False, type='bool'), + kubeconfig=dict(default='/etc/origin/master/admin.kubeconfig', type='str'), + backup=dict(default=True, type='bool'), + force=dict(default=False, type='bool'), + # oc adm ca create-server-cert [options] + cert=dict(default=None, type='str'), + key=dict(default=None, type='str'), + signer_cert=dict(default='/etc/origin/master/ca.crt', type='str'), + signer_key=dict(default='/etc/origin/master/ca.key', type='str'), + signer_serial=dict(default='/etc/origin/master/ca.serial.txt', type='str'), + hostnames=dict(default=[], type='list'), + ), + supports_check_mode=True, + ) + + results = CAServerCert.run_ansible(module.params, module.check_mode) + if 'failed' in results: + return module.fail_json(**results) + + return module.exit_json(**results) + + +if __name__ == '__main__': + main() diff --git a/roles/lib_openshift/src/class/oc_adm_ca_server_cert.py b/roles/lib_openshift/src/class/oc_adm_ca_server_cert.py new file mode 100644 index 000000000..6ed1f2f35 --- /dev/null +++ b/roles/lib_openshift/src/class/oc_adm_ca_server_cert.py @@ -0,0 +1,135 @@ +# pylint: skip-file +# flake8: noqa + +class CAServerCertConfig(OpenShiftCLIConfig): + ''' CAServerCertConfig is a DTO for the oc adm ca command ''' + def __init__(self, kubeconfig, verbose, ca_options): + super(CAServerCertConfig, self).__init__('ca', None, kubeconfig, ca_options) + self.kubeconfig = kubeconfig + self.verbose = verbose + self._ca = ca_options + + +class CAServerCert(OpenShiftCLI): + ''' Class to wrap the oc adm ca create-server-cert command line''' + def __init__(self, + config, + verbose=False): + ''' Constructor for oadm ca ''' + super(CAServerCert, self).__init__(None, config.kubeconfig, verbose) + self.config = config + self.verbose = verbose + + def get(self): + '''get the current cert file + + If a file exists by the same name in the specified location then the cert exists + ''' + cert = self.config.config_options['cert']['value'] + if cert and os.path.exists(cert): + return open(cert).read() + + return None + + def create(self): + '''run openshift oc adm ca create-server-cert cmd''' + + # Added this here as a safegaurd for stomping on the + # cert and key files if they exist + if self.config.config_options['backup']['value']: + import time + ext = time.strftime("%Y-%m-%d@%H:%M:%S", time.localtime(time.time())) + date_str = "%s_" + "%s" % ext + + if os.path.exists(self.config.config_options['key']['value']): + shutil.copy(self.config.config_options['key']['value'], + date_str % self.config.config_options['key']['value']) + if os.path.exists(self.config.config_options['cert']['value']): + shutil.copy(self.config.config_options['cert']['value'], + date_str % self.config.config_options['cert']['value']) + + options = self.config.to_option_list() + + cmd = ['ca', 'create-server-cert'] + cmd.extend(options) + + return self.openshift_cmd(cmd, oadm=True) + + def exists(self): + ''' check whether the certificate exists and has the clusterIP ''' + + cert_path = self.config.config_options['cert']['value'] + if not os.path.exists(cert_path): + return False + + # Would prefer pyopenssl but is not installed. + # When we verify it is, switch this code + # Here is the code to get the subject and the SAN + # openssl x509 -text -noout -certopt \ + # no_header,no_version,no_serial,no_signame,no_validity,no_issuer,no_pubkey,no_sigdump,no_aux \ + # -in /etc/origin/master/registry.crt + # Instead of this solution we will use a regex. + cert_names = [] + hostnames = self.config.config_options['hostnames']['value'].split(',') + proc = subprocess.Popen(['openssl', 'x509', '-noout', '-text', '-in', cert_path], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + x509output, _ = proc.communicate() + if proc.returncode == 0: + regex = re.compile(r"^\s*X509v3 Subject Alternative Name:\s*?\n\s*(.*)\s*\n", re.MULTILINE) + match = regex.search(x509output) # E501 + for entry in re.split(r", *", match.group(1)): + if entry.startswith('DNS') or entry.startswith('IP Address'): + cert_names.append(entry.split(':')[1]) + # now that we have cert names let's compare + cert_set = set(cert_names) + hname_set = set(hostnames) + if cert_set.issubset(hname_set) and hname_set.issubset(cert_set): + return True + + return False + + @staticmethod + def run_ansible(params, check_mode): + '''run the idempotent ansible code''' + + config = CAServerCertConfig(params['kubeconfig'], + params['debug'], + {'cert': {'value': params['cert'], 'include': True}, + 'hostnames': {'value': ','.join(params['hostnames']), 'include': True}, + 'overwrite': {'value': True, 'include': True}, + 'key': {'value': params['key'], 'include': True}, + 'signer_cert': {'value': params['signer_cert'], 'include': True}, + 'signer_key': {'value': params['signer_key'], 'include': True}, + 'signer_serial': {'value': params['signer_serial'], 'include': True}, + 'backup': {'value': params['backup'], 'include': False}, + }) + + server_cert = CAServerCert(config) + + state = params['state'] + + if state == 'present': + ######## + # Create + ######## + if not server_cert.exists() or params['force']: + + if check_mode: + return {'changed': True, + 'msg': "CHECK_MODE: Would have created the certificate.", + 'state': state} + + api_rval = server_cert.create() + + return {'changed': True, 'results': api_rval, 'state': state} + + ######## + # Exists + ######## + api_rval = server_cert.get() + return {'changed': False, 'results': api_rval, 'state': state} + + return {'failed': True, + 'msg': 'Unknown state passed. %s' % state} + diff --git a/roles/lib_openshift/src/doc/ca_server_cert b/roles/lib_openshift/src/doc/ca_server_cert new file mode 100644 index 000000000..a8034158e --- /dev/null +++ b/roles/lib_openshift/src/doc/ca_server_cert @@ -0,0 +1,96 @@ +# flake8: noqa +# pylint: skip-file + +DOCUMENTATION = ''' +--- +module: oc_adm_ca_server_cert +short_description: Module to run openshift oc adm ca create-server-cert +description: + - Wrapper around the openshift `oc adm ca create-server-cert` command. +options: + state: + description: + - Present is the only supported state. The state present means that `oc adm ca` will generate a certificate + - and verify if the hostnames and the ClusterIP exists in the certificate. + - When create-server-cert is desired then the following parameters are passed. + - ['cert', 'key', 'signer_cert', 'signer_key', 'signer_serial'] + required: false + default: present + choices: + - present + aliases: [] + kubeconfig: + description: + - The path for the kubeconfig file to use for authentication + required: false + default: /etc/origin/master/admin.kubeconfig + aliases: [] + debug: + description: + - Turn on debug output. + required: false + default: False + aliases: [] + cert: + description: + - The certificate file. Choose a name that indicates what the service is. + required: false + default: None + aliases: [] + key: + description: + - The key file. Choose a name that indicates what the service is. + required: false + default: None + aliases: [] + force: + description: + - Force updating of the existing cert and key files + required: false + default: False + aliases: [] + signer_cert: + description: + - The signer certificate file. + required: false + default: /etc/origin/master/ca.crt + aliases: [] + signer_key: + description: + - The signer key file. + required: false + default: /etc/origin/master/ca.key + aliases: [] + signer_serial: + description: + - The signer serial file. + required: false + default: /etc/origin/master/ca.serial.txt + aliases: [] + hostnames: + description: + - Every hostname or IP that server certs should be valid for (comma-delimited list) + required: false + default: None + aliases: [] + backup: + description: + - Whether to backup the cert and key files before writing them. + required: false + default: True + aliases: [] +author: +- "Kenny Woodson <kwoodson@redhat.com>" +extends_documentation_fragment: [] +''' + +EXAMPLES = ''' +- name: Create a self-signed cert + oc_adm_ca_server_cert: + signer_cert: /etc/origin/master/ca.crt + signer_key: /etc/origin/master/ca.key + signer_serial: /etc/origin/master/ca.serial.txt + hostnames: "registry.test.openshift.com,127.0.0.1,docker-registry.default.svc.cluster.local" + cert: /etc/origin/master/registry.crt + key: /etc/origin/master/registry.key +''' diff --git a/roles/lib_openshift/src/sources.yml b/roles/lib_openshift/src/sources.yml index fca1f4818..35f8d71b2 100644 --- a/roles/lib_openshift/src/sources.yml +++ b/roles/lib_openshift/src/sources.yml @@ -1,4 +1,14 @@ --- +oc_adm_ca_server_cert.py: +- doc/generated +- doc/license +- lib/import.py +- doc/ca_server_cert +- ../../lib_utils/src/class/yedit.py +- lib/base.py +- class/oc_adm_ca_server_cert.py +- ansible/oc_adm_ca_server_cert.py + oadm_manage_node.py: - doc/generated - doc/license |