From 997d408f718d651a3e679cd2c17fd5ba02e4043a Mon Sep 17 00:00:00 2001 From: Leonardo Rossetti Date: Sep 24 2021 13:35:35 +0000 Subject: cert generation re-factor --- diff --git a/operator/molecule/default/tasks/kojihub_test.yml b/operator/molecule/default/tasks/kojihub_test.yml index 625d636..a546147 100644 --- a/operator/molecule/default/tasks/kojihub_test.yml +++ b/operator/molecule/default/tasks/kojihub_test.yml @@ -70,7 +70,6 @@ - assert: that: - kojihub_secrets.resources|length == 1 - - kojihub_secrets.resources[0].metadata.labels['app'] == 'koji-hub' - "'client.pem' in kojihub_secrets.resources[0].data" - block: diff --git a/operator/requirements.yml b/operator/requirements.yml index de1ec48..06fe6d2 100644 --- a/operator/requirements.yml +++ b/operator/requirements.yml @@ -1,6 +1,6 @@ --- collections: - - name: community.kubernetes + - name: kubernetes.core version: "1.2.1" - name: operator_sdk.util version: "0.2.0" diff --git a/operator/roles/koji-builder/tasks/builders/repo.yml b/operator/roles/koji-builder/tasks/builders/repo.yml index c93aa24..d6dcd08 100644 --- a/operator/roles/koji-builder/tasks/builders/repo.yml +++ b/operator/roles/koji-builder/tasks/builders/repo.yml @@ -1,4 +1,22 @@ --- +- name: Retrieve CA secret + k8s_info: + api_version: v1 + kind: Secret + name: "{{ koji_builder_cacert_secret }}" + namespace: "{{ meta.namespace }}" + register: k8s_secrets + +- name: Fail if CA secret is not found + fail: + msg: "Secret {{ koji_builder_cacert_secret }} not found." + when: k8s_secrets.resources|length == 0 + +- name: Copy CA certificate to temporary folder + copy: + content: "{{ k8s_secrets.resources[0].data.cert | b64decode }}" + dest: "{{ koji_dir_path }}/ca.pem" + - block: - name: Download admin client certificate k8s_info: @@ -18,7 +36,7 @@ - koji_host: server: "{{ koji_builder_koji_hub_url }}/kojihub" - host: "{{ koji_builder_host_name }}" + host: "{{ meta.name }}" archs: "{{ koji_builder_host_archs }}" channels: [ "createrepo" ] ssl_auth: diff --git a/operator/roles/koji-builder/tasks/cert.yml b/operator/roles/koji-builder/tasks/cert.yml index 5da5e05..e009871 100644 --- a/operator/roles/koji-builder/tasks/cert.yml +++ b/operator/roles/koji-builder/tasks/cert.yml @@ -1,66 +1,8 @@ -- name: Check for koji-builder client secret existence - k8s_info: - api_version: v1 - kind: Secret - name: "{{ koji_builder_client_cert_secret }}" - namespace: "{{ meta.namespace }}" - register: clientcert_query - -- name: Retrieve ca secret - block: - - k8s_info: - api_version: v1 - kind: Secret - name: "{{ koji_builder_cacert_secret }}" - namespace: "{{ meta.namespace }}" - register: k8s_secrets - - fail: - msg: "Secret {{ koji_builder_cacert_secret }} not found." - when: k8s_secrets.resources|length == 0 - - set_fact: - ca: "{{ k8s_secrets.resources[0] }}" - - copy: - content: "{{ ca.data.cert | b64decode }}" - dest: "{{ koji_dir_path }}/ca_cert.pem" - - copy: - content: "{{ ca.data.key | b64decode }}" - dest: "{{ koji_dir_path }}/ca_key.pem" - when: clientcert_query.resources|length == 0 - - copy: - content: "{{ ca.data.cert | b64decode }}" - dest: "{{ koji_dir_path }}/ca.pem" - -- name: Client certificate creation - block: - - openssl_privatekey: - path: "{{ koji_dir_path }}/client_key.pem" - size: 4096 - - openssl_csr: - path: "{{ koji_dir_path }}/client_req.pem" - privatekey_path: "{{ koji_dir_path }}/client_key.pem" - common_name: "{{ koji_builder_host_name }}" - - openssl_certificate: - path: "{{ koji_dir_path }}/client_cert.pem" - csr_path: "{{ koji_dir_path }}/client_req.pem" - ownca_path: "{{ koji_dir_path }}/ca_cert.pem" - ownca_privatekey_path: "{{ koji_dir_path }}/ca_key.pem" - provider: ownca - when: clientcert_query.resources|length == 0 - -- name: Kubernetes client certificate secret creation - block: - - k8s: - definition: - apiVersion: v1 - kind: Secret - metadata: - name: "{{ koji_builder_client_cert_secret }}" - namespace: "{{ meta.namespace }}" - labels: - app: koji-builder - data: - # tls.crt: "{{ lookup('file', koji_dir_path + '/client_cert.pem') | b64encode }}" - # tls.key: "{{ lookup('file', koji_dir_path + '/client_key.pem') | b64encode }}" - client.pem: "{{ (lookup('file', koji_dir_path + '/client_key.pem') + '\n' + lookup('file', koji_dir_path + '/client_cert.pem')) | b64encode }}" - when: clientcert_query.resources|length == 0 - +- koji_client_cert: + k8s_ca: "{{ meta.namespace }}/{{ koji_builder_cacert_secret }}" + k8s_cert: "{{ meta.namespace }}/{{ koji_builder_client_cert_secret }}" + k8s_meta: + labels: + app: koji-builder + username: "{{ meta.name }}" + force: false diff --git a/operator/roles/koji-builder/tasks/main.yml b/operator/roles/koji-builder/tasks/main.yml index 87e91a8..f7ee336 100644 --- a/operator/roles/koji-builder/tasks/main.yml +++ b/operator/roles/koji-builder/tasks/main.yml @@ -22,7 +22,6 @@ src: "{{ koji_dir_path }}/configmap.yml" wait: true namespace: "{{ meta.namespace }}" - - include_tasks: builders/repo.yml when: "koji_builder_type == 'repo'" diff --git a/operator/roles/koji-certs/tasks/main.yml b/operator/roles/koji-certs/tasks/main.yml new file mode 100644 index 0000000..354d2dd --- /dev/null +++ b/operator/roles/koji-certs/tasks/main.yml @@ -0,0 +1,9 @@ +--- +""" +koji_ca_k8s: '$name/$namespace' +koji_cert_dir: '' +koji_cert_cn: '' +koji_cert_client_cert: '$name/$namespace' +koji_cert_state: 'present|absent' +koji_cert_force: true|false +""" diff --git a/operator/roles/koji-hub/meta/main.yml b/operator/roles/koji-hub/meta/main.yml new file mode 100644 index 0000000..a2634aa --- /dev/null +++ b/operator/roles/koji-hub/meta/main.yml @@ -0,0 +1,2 @@ +dependencies: + - role: koji-lib diff --git a/operator/roles/koji-hub/tasks/cert.yml b/operator/roles/koji-hub/tasks/cert.yml index 8e0ac06..da11203 100644 --- a/operator/roles/koji-hub/tasks/cert.yml +++ b/operator/roles/koji-hub/tasks/cert.yml @@ -10,11 +10,6 @@ suffix: cert register: cert_dir - # - block: - #- set_fact: - # koji_hub_ca_cert_secret: "{{ k8s_mboxes.resources[0].spec.root_ca_secret_name }}" - #when: koji_mbox|length > 0 - # koji-hub ca cert - name: Root CA creation k8s_info: @@ -107,78 +102,28 @@ when: k8s_servicecert_query.resources|length == 0 # koji-hub admin client cert -- name: check if admin client cert exists - k8s_info: - api_version: v1 - kind: Secret - name: "{{ koji_hub_admin_client_cert }}" - namespace: "{{ meta.namespace }}" - register: k8s_admin_cert_query -- block: - - name: Admin user certificate creation - openssl_privatekey: - path: "{{ cert_dir.path }}/admin_key.pem" - size: 4096 - - openssl_csr: - path: "{{ cert_dir.path }}/admin_req.pem" - privatekey_path: "{{ cert_dir.path }}/admin_key.pem" - common_name: "{{ koji_hub_admin_username }}" - - openssl_certificate: - path: "{{ cert_dir.path }}/admin_cert.pem" - csr_path: "{{ cert_dir.path }}/admin_req.pem" - ownca_path: "{{ cert_dir.path }}/ca_cert.pem" - ownca_privatekey_path: "{{ cert_dir.path }}/ca_key.pem" - provider: ownca - - k8s: - definition: - apiVersion: v1 - kind: Secret - metadata: - name: "{{ koji_hub_admin_client_cert }}" - namespace: "{{ meta.namespace }}" - labels: - app: koji-hub - data: - client.pem: "{{ (lookup('file', cert_dir.path + '/admin_key.pem') + '\n' + lookup('file', cert_dir.path + '/admin_cert.pem')) | b64encode }}" - - copy: - content: "{{ lookup('file', cert_dir.path + '/admin_key.pem') + '\n' + lookup('file', cert_dir.path + '/admin_cert.pem') }}" - dest: "{{ lookup('env', 'HOME') }}/.koji/certs/{{ meta.name }}/client.pem" - when: k8s_admin_cert_query.resources|length == 0 +- name: Create kojiadmin client cert + koji_client_cert: + k8s_ca: "{{ meta.namespace }}/{{ koji_hub_ca_cert_secret }}" + k8s_cert: "{{ meta.namespace }}/{{ koji_hub_admin_client_cert }}" + username: "{{ koji_hub_admin_username }}" + force: false + state: present + register: koji_hub_admin_cert + +- copy: + content: "{{ koji_hub_admin_cert.result.pemfile }}" + dest: "{{ lookup('env', 'HOME') }}/.koji/certs/{{ meta.name }}/client.pem" + when: koji_hub_admin_cert.changed # koji-web client cert -- name: check if kojiweb client cert exists - k8s_info: - api_version: v1 - kind: Secret - name: "{{ koji_hub_web_client_cert }}" - namespace: "{{ meta.namespace }}" - register: k8s_web_cert_query -- block: - - openssl_privatekey: - path: "{{ cert_dir.path }}/client_web_key.pem" - size: 4096 - - openssl_csr: - path: "{{ cert_dir.path }}/client_web_req.pem" - privatekey_path: "{{ cert_dir.path }}/client_web_key.pem" - common_name: "{{ koji_hub_web_client_username }}" - - openssl_certificate: - path: "{{ cert_dir.path }}/client_web_cert.pem" - csr_path: "{{ cert_dir.path }}/client_web_req.pem" - ownca_path: "{{ cert_dir.path }}/ca_cert.pem" - ownca_privatekey_path: "{{ cert_dir.path }}/ca_key.pem" - provider: ownca - - k8s: - definition: - apiVersion: v1 - kind: Secret - metadata: - name: "{{ koji_hub_web_client_cert }}" - namespace: "{{ meta.namespace }}" - labels: - app: koji-hub - data: - client.pem: "{{ (lookup('file', cert_dir.path + '/client_web_key.pem') + '\n' + lookup('file', cert_dir.path + '/client_web_cert.pem')) | b64encode }}" - when: k8s_web_cert_query.resources|length == 0 +- name: Create kojiweb client cert + koji_client_cert: + k8s_ca: "{{ meta.namespace }}/{{ koji_hub_ca_cert_secret }}" + k8s_cert: "{{ meta.namespace }}/{{ koji_hub_web_client_cert }}" + username: "{{ koji_hub_web_client_cert }}" + force: false + state: present - name: cleanup file: diff --git a/operator/roles/koji-lib/action_plugins/koji_client_cert.py b/operator/roles/koji-lib/action_plugins/koji_client_cert.py new file mode 100644 index 0000000..e97d74d --- /dev/null +++ b/operator/roles/koji-lib/action_plugins/koji_client_cert.py @@ -0,0 +1,289 @@ +# This file is part of the koji-operator project. +# Copyright (C) 2020 Red Hat, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +DOCUMENTATION = ''' +--- +module: koji_client_cert + +short_description: Ansible module that creates a client certificate for koji access. + +description: + - This is an action plugin that uses several ansible modules (openssl + kubernetes) + - This module loads the root CA from kubernetes and creates signs a new certificate from it + - It uses the username as the certfificate common name + - It creates the a kubernetes secret with both the private key and certificate in a single file (client.pem) + - It returns both client.pem content and the kubernetes secret resource + +options: + k8s_ca: + description: + - the kubernetes ca secret namespace and name ($NAMESPACE/$NAME) + required: true + k8s_secret: + description: + - the kubernetes client secret namespace and name ($NAMESPACE/$NAME) to be created + - it will skip the module run if a secret already exists and 'force' is set to false + k8s_meta: + description: + - A dicitonary indicating any extra fields to add into the secret "metadata" data; + - labels, annotations, etc. + required: false + username: + description: + - the common name to be used in the certificate (it needs to be the same username used in koji) + required: true + force: + description: + - A boolean flag that will re-create the kubernetes client secret in case one was already created with the same name + default: false + +author: + - Red Hat, Inc. and others +''' + +EXAMPLES = ''' +- koji_client_cert: + k8s_ca: koji/koji-hub-ca + k8s_cert: "koji/koji-web-client-cert + k8s_meta: + labels: + app: myapp + annotations: + a: 2 + username: kojiweb + force: false +''' + + +from pathlib import Path +from base64 import b64encode, b64decode + +import yaml +from ansible.plugins.action import ActionBase + + +class ActionModule(ActionBase): + def create_subdirs(self): + """Create directories in the run tmp folder""" + tmpdir = self._connection._shell.tmpdir + Path(f'{tmpdir}/certs/ca').mkdir(parents=True, exist_ok=True) + Path(f'{tmpdir}/certs/client').mkdir(parents=True, exist_ok=True) + Path(f'{tmpdir}/k8s').mkdir(parents=True, exist_ok=True) + + def file_write(self, path, data): + """Helper function to write a file""" + with open(path, 'w+') as f: + f.write(str(data)) + + def file_read(self, path): + """Helper function to read from a file""" + with open(path, 'r') as f: + return f.read() + + def run_setup(self, task_vars=None): + """Runs the setup module""" + self._execute_module( + 'setup', + module_args=dict( + gather_subset='all', + gather_timeout=10 + ), + task_vars=task_vars + ) + def run_k8s_info(self, api_version, kind, ref, task_vars=None): + """Runs the k8s_info module""" + namespace, name = ref.split('/') + + res = self._execute_module( + 'kubernetes.core.k8s', + module_args=dict( + api_version=api_version, + kind=kind, + namespace=namespace, + name=name), + task_vars=task_vars) + + if res.get('failed'): + return None + + if len(res.get('result', {}).get('data', {})) == 0: + return None + + return res.get('result') + + def run_private_key(self, basedir, key_size=4096, task_vars=None): + """Runs the openssl_privatekey module""" + return self._execute_module( + 'ansible.builtin.openssl_privatekey', + module_args=dict( + path=f'{basedir}/certs/client/key.pem', + size=key_size + ), + task_vars=task_vars + ) + + def run_openssl_csr(self, basedir, private_key, common_name, task_vars=None): + return self._execute_module( + 'ansible.builtin.openssl_csr', + module_args=dict( + path=f'{basedir}/certs/client/request.csr', + privatekey_path=private_key, + common_name=common_name + ), + task_vars=task_vars + ) + + def run_openssl_certificate(self, basedir, task_vars=None): + return self._execute_module( + 'ansible.builtin.openssl_certificate', + module_args=dict( + path=f'{basedir}/certs/client/cert.pem', + csr_path=f'{basedir}/certs/client/request.csr', + ownca_path=f'{basedir}/certs/ca/cert.pem', + ownca_privatekey_path=f'{basedir}/certs/ca/key.pem', + provider='ownca' + ), + task_vars=task_vars + ) + + def run_k8s(self, data, ref, task_vars=None): + namespace, name = ref.split('/') + + return self._execute_module( + 'kubernetes.core.k8s', + module_args=dict( + state='present', + definition=data + ), + task_vars=task_vars + ) + + def run(self, tmp=None, task_vars=None): + super(ActionModule, self).run(tmp, task_vars) + + output = { + 'failed': False, + 'changed': False, + 'skipped': False, + 'msg': '', + 'result': {} + } + + # plugin params + module_args = self._task.args.copy() + + param_k8s_ca = module_args.get('k8s_ca') + param_k8s_cert = module_args.get('k8s_cert') + param_username = module_args.get('username') + param_force = module_args.get('force', False) + param_k8s_meta = module_args.get('k8s_meta', {}) + + # run setup module so facts are gathered + self.run_setup(task_vars) + self.create_subdirs() + tmpdir = self._connection._shell.tmpdir + + # retrieves an existing client cert (if any) + # skips the run in case a secret is found + # it won't skip if "force" is set to True + k8s_cert = self.run_k8s_info('v1', 'Secret', param_k8s_cert, task_vars=task_vars) + if k8s_cert is not None and not param_force: + output['skipped'] = True + output['msg'] = f'Secret {param_k8s_cert} already exists' + return output + + # retrieves the root ca secret from kubernetes + # fails if no secret is found + # fails if secret does not have the expected format + k8s_ca = self.run_k8s_info('v1', 'Secret', param_k8s_ca, task_vars=task_vars) + if k8s_ca is None: + output['failed'] = True + output['msg'] = f'Secret {param_k8s_ca} not found' + return output + if k8s_ca.get('data', {}).get('cert', None) is None: + output['failed'] = True + output['msg'] = f'Secret {param_k8s_ca} cannot be parsed' + return output + + # writes ca cert and key to tmp task folder + ca_cert = self.file_write(f'{tmpdir}/certs/ca/cert.pem', b64decode(k8s_ca['data']['cert']).decode()) + ca_key = self.file_write(f'{tmpdir}/certs/ca/key.pem', b64decode(k8s_ca['data']['key']).decode()) + + # creates the client private key + private_key = self.run_private_key( + f'{tmpdir}', + task_vars=task_vars + ) + if private_key.get('failed'): + output['failed'] = True + output['msg'] = private_key['msg'] + return output + + # create client csr + csr = self.run_openssl_csr( + f'{tmpdir}', + private_key['filename'], + param_username, + task_vars=task_vars) + if csr.get('failed'): + output['failed'] = True + output['msg'] = csr['msg'] + return output + + # create client certificate + cert = self.run_openssl_certificate(tmpdir, task_vars=task_vars) + if cert.get('failed'): + output['failed'] = True + output['msg'] = cert['msg'] + return output + + # create k8s cert secret + client_pem = self.file_read(private_key['filename']) + self.file_read(cert['filename']) + k8s_cert_namespace, k8s_cert_name = param_k8s_cert.split('/') + k8s_secret_res = { + 'apiVersion': 'v1', + 'kind': 'Secret', + 'metadata': { + 'name': k8s_cert_name, + 'namespace': k8s_cert_namespace, + 'labels': { + 'app': 'koji' + } + }, + 'data': { + 'client.pem': b64encode(client_pem.encode()).decode() + } + } + for k,v in param_k8s_meta.items(): + k8s_secret_res['metadata'][k] = v + + k8s_client_secret = self.run_k8s(k8s_secret_res, param_k8s_cert, task_vars=task_vars) + + # set response dict + output['changed'] = True + output['msg'] = f'Secret {param_k8s_cert} created' + output['result'] = { + 'pemfile': client_pem, + 'k8s': k8s_client_secret['result'] + } + + return output + diff --git a/operator/roles/koji-lib/tests/ansible.cfg b/operator/roles/koji-lib/tests/ansible.cfg new file mode 100644 index 0000000..8a73491 --- /dev/null +++ b/operator/roles/koji-lib/tests/ansible.cfg @@ -0,0 +1,2 @@ +[defaults] +action_plugins = ~/.ansible/plugins/action:/usr/share/ansible/plugins/action:../action_plugins diff --git a/operator/roles/koji-lib/tests/main.yaml b/operator/roles/koji-lib/tests/main.yaml new file mode 100644 index 0000000..77f0a4d --- /dev/null +++ b/operator/roles/koji-lib/tests/main.yaml @@ -0,0 +1,61 @@ +- hosts: localhost + connection: local + collections: + - community.kubernetes + gather_facts: false + tasks: + - name: Create temporary cert directory + tempfile: + state: directory + prefix: kojilib + suffix: cert + register: cert_dir + + - name: Create CA private key + openssl_privatekey: + path: "{{ cert_dir.path }}/ca_key.pem" + size: 4096 + + - name: Create CA CSR + openssl_csr: + path: "{{ cert_dir.path }}/ca_req.pem" + privatekey_path: "{{ cert_dir.path }}/ca_key.pem" + common_name: localhost + create_subject_key_identifier: true + key_usage: + - cRLSign + - dataEncipherment + - digitalSignature + - keyCertSign + - keyEncipherment + - nonRepudiation + basic_constraints: + - 'CA:TRUE' + + - name: Create CA certifiate + openssl_certificate: + path: "{{ cert_dir.path }}/ca_cert.pem" + privatekey_path: "{{ cert_dir.path }}/ca_key.pem" + csr_path: "{{ cert_dir.path }}/ca_req.pem" + provider: selfsigned + + - name: Create CA kubernetes secret + k8s: + definition: + apiVersion: v1 + kind: Secret + metadata: + name: ca + namespace: default + data: + csr: "{{ lookup('file', cert_dir.path + '/ca_req.pem') | b64encode }}" + cert: "{{ lookup('file', cert_dir.path + '/ca_cert.pem') | b64encode }}" + key: "{{ lookup('file', cert_dir.path + '/ca_key.pem') | b64encode }}" + + - name: Create a koji client secret + koji_client_cert: + k8s_ca: default/ca + k8s_cert: default/client + username: builder + force: false + state: present diff --git a/operator/roles/koji-lib/tests/requirements.yml b/operator/roles/koji-lib/tests/requirements.yml new file mode 100644 index 0000000..7ba24a0 --- /dev/null +++ b/operator/roles/koji-lib/tests/requirements.yml @@ -0,0 +1,4 @@ +--- +collections: + - name: community.kubernetes + version: "1.2.1" diff --git a/operator/roles/kojira/tasks/cert.yml b/operator/roles/kojira/tasks/cert.yml index 0717ac6..8c379d9 100644 --- a/operator/roles/kojira/tasks/cert.yml +++ b/operator/roles/kojira/tasks/cert.yml @@ -12,73 +12,14 @@ suffix: koji register: koji_dir -- block: - - set_fact: - kojira_cacert_secret: "{{ k8s_mboxes.resources[0].spec.root_ca_secret_name }}" - when: kojira_builder_mbox|length > 0 - -- k8s_info: - api_version: v1 - kind: Secret - name: "{{ kojira_client_cert_secret }}" - namespace: "{{ meta.namespace }}" - register: clientcert_query - -- name: Retrieve ca secret - block: - - k8s_info: - api_version: v1 - kind: Secret - name: "{{ kojira_cacert_secret }}" - namespace: "{{ meta.namespace }}" - register: k8s_secrets - - fail: - msg: "Secret {{ kojira_cacert_secret }} not found." - when: k8s_secrets.resources|length == 0 - - set_fact: - ca: "{{ k8s_secrets.resources[0] }}" - - copy: - content: "{{ ca.data.cert | b64decode }}" - dest: "{{ cert_dir.path }}/ca_cert.pem" - - copy: - content: "{{ ca.data.key | b64decode }}" - dest: "{{ cert_dir.path }}/ca_key.pem" - when: clientcert_query.resources|length == 0 - - copy: - content: "{{ ca.data.cert | b64decode }}" - dest: "{{ koji_dir.path }}/ca.pem" - -- name: Client certificate creation - block: - - openssl_privatekey: - path: "{{ cert_dir.path }}/client_key.pem" - size: 4096 - - openssl_csr: - path: "{{ cert_dir.path }}/client_req.pem" - privatekey_path: "{{ cert_dir.path }}/client_key.pem" - common_name: "{{ kojira_hub_username }}" - - openssl_certificate: - path: "{{ cert_dir.path }}/client_cert.pem" - csr_path: "{{ cert_dir.path }}/client_req.pem" - ownca_path: "{{ cert_dir.path }}/ca_cert.pem" - ownca_privatekey_path: "{{ cert_dir.path }}/ca_key.pem" - provider: ownca - when: clientcert_query.resources|length == 0 - -- name: Kubernetes client certificate secret creation - block: - - k8s: - definition: - apiVersion: v1 - kind: Secret - metadata: - name: "{{ kojira_client_cert_secret }}" - namespace: "{{ meta.namespace }}" - labels: - app: kojira - data: - client.pem: "{{ (lookup('file', cert_dir.path + '/client_key.pem') + '\n' + lookup('file', cert_dir.path + '/client_cert.pem')) | b64encode }}" - when: clientcert_query.resources|length == 0 +- koji_client_cert: + k8s_ca: "{{ meta.namespace }}/{{ kojira_cacert_secret }}" + k8s_cert: "{{ meta.namespace }}/{{ kojira_client_cert_secret }}" + k8s_meta: + labels: + app: kojira + username: "{{ kojira_hub_username }}" + force: false - name: cleanup file: diff --git a/operator/roles/kojira/tasks/main.yml b/operator/roles/kojira/tasks/main.yml index a64b67d..a1258cf 100644 --- a/operator/roles/kojira/tasks/main.yml +++ b/operator/roles/kojira/tasks/main.yml @@ -6,19 +6,6 @@ suffix: deploy register: kojira_dir -- block: - - name: retrieve mbox resource - k8s_info: - api_version: apps.fedoraproject.org/v1alpha1 - kind: Mbox - namespace: "{{ meta.namespace }}" - name: "{{ kojira_builder_mbox }}" - register: k8s_mboxes - - fail: - msg: "Failed to find mbox {{ kojira_builder_mbox }} in namespace {{ meta.namespace }}" - when: k8s_mboxes.resources|length == 0 - when: kojira_builder_mbox|length > 0 - - include_tasks: cert.yml - block: diff --git a/operator/roles/kojiuser/meta/main.yml b/operator/roles/kojiuser/meta/main.yml index 032b390..a2634aa 100644 --- a/operator/roles/kojiuser/meta/main.yml +++ b/operator/roles/kojiuser/meta/main.yml @@ -1,2 +1,2 @@ -#dependencies: -# - role: ktdreyer.koji_ansible +dependencies: + - role: koji-lib diff --git a/operator/roles/kojiuser/tasks/create.yml b/operator/roles/kojiuser/tasks/create.yml index 84064a4..8c8a6e7 100644 --- a/operator/roles/kojiuser/tasks/create.yml +++ b/operator/roles/kojiuser/tasks/create.yml @@ -23,76 +23,23 @@ state: enabled - block: - - name: create temporary cert directory + - name: Create user secret k8s_info: api_version: buildsys.apps.fedoraproject.org/v1alpha1 kind: KojiHub namespace: "{{ koji_user_hub_namespace }}" name: "{{ koji_user_hub_name }}" register: k8s_query - - fail: - msg: "Failed to retrieve koji-hub" - when: k8s_query.resources | length == 0 - - k8s_info: - api_version: v1 - kind: Secret - namespace: "{{ koji_user_hub_namespace }}" - name: "{{ k8s_query.resources[0]['spec']['ca_cert_secret'] }}" - register: k8s_secret - - fail: - msg: 'Could not fetch ca secret' - when: k8s_secret.resources | length == 0 - - tempfile: - state: directory - prefix: kojiuser - suffix: cert - register: cert_dir - - copy: - content: "{{ k8s_secret.resources[0].data.cert | b64decode }}" - dest: "{{ cert_dir.path }}/ca_cert.pem" - - copy: - content: "{{ k8s_secret.resources[0].data.key | b64decode }}" - dest: "{{ cert_dir.path }}/ca_key.pem" - - k8s_info: - api_version: v1 - kind: Secret - name: "{{ meta.name }}-koji-client-cert" - namespace: "{{ meta.namespace }}" - register: clientcert_query - - openssl_privatekey: - path: "{{ cert_dir.path }}/client_key.pem" - size: 4096 - when: clientcert_query.resources|length == 0 - - openssl_csr: - path: "{{ cert_dir.path }}/client_req.pem" - privatekey_path: "{{ cert_dir.path }}/client_key.pem" - common_name: "{{ meta.name }}" - when: clientcert_query.resources|length == 0 - - openssl_certificate: - path: "{{ cert_dir.path }}/client_cert.pem" - csr_path: "{{ cert_dir.path }}/client_req.pem" - ownca_path: "{{ cert_dir.path }}/ca_cert.pem" - ownca_privatekey_path: "{{ cert_dir.path }}/ca_key.pem" - provider: ownca - when: clientcert_query.resources|length == 0 - - k8s: - definition: - apiVersion: v1 - kind: Secret - metadata: - name: "{{ meta.name }}-koji-client-cert" - namespace: "{{ meta.namespace }}" - labels: - app: koji - koji-hub: "{{ koji_user_hub_name }}" - annotations: - buildsys.apps.fedoraproject.org/hub: "{{ koji_user_hub_name }}/{{ koji_user_hub_namespace }}" - data: - client.pem: "{{ (lookup('file', cert_dir.path + '/client_key.pem') + '\n' + lookup('file', cert_dir.path + '/client_cert.pem')) | b64encode }}" - when: clientcert_query.resources|length == 0 - - name: cleanup - file: - path: "{{ cert_dir.path }}" - state: absent - when: - - koji_user_ssl + + - koji_client_cert: + k8s_ca: "{{ koji_user_hub_namespace }}/{{ k8s_query.resources[0]['spec']['ca_cert_secret'] }}" + k8s_cert: "{{ meta.namespace }}/{{ meta.name }}-koji-client-cert" + k8s_meta: + labels: + app: koji + koji-hub: "{{ koji_user_hub_name }}" + annotations: + buildsys.apps.fedoraproject.org/hub: "{{ koji_user_hub_name }}/{{ koji_user_hub_namespace }}" + username: "{{ koji_user_hub_name }}" + force: false + when: koji_user_ssl