diff --git a/roles/cockpit-ui/defaults/main.yml b/roles/cockpit-ui/defaults/main.yml index b1696f1b88a..c31e409b998 100644 --- a/roles/cockpit-ui/defaults/main.yml +++ b/roles/cockpit-ui/defaults/main.yml @@ -1,3 +1,4 @@ --- openshift_config_base: "/etc/origin" openshift_master_config_dir: "{{ openshift.common.config_base | default(openshift_config_base) }}/master" +openshift_hosted_registry_console_cert_expire_days: 730 diff --git a/roles/cockpit-ui/tasks/main.yml b/roles/cockpit-ui/tasks/main.yml index 244e2cc4138..4729f25f52c 100644 --- a/roles/cockpit-ui/tasks/main.yml +++ b/roles/cockpit-ui/tasks/main.yml @@ -1,41 +1,47 @@ --- - block: + - name: Configure facts for registry-console + set_fact: + openshift_hosted_registry_console_namespace: "{{ ('namespace' in openshift.hosted.registry.console.keys()) | ternary(openshift.hosted.registry.console.namespace, 'default') }}" + openshift_hosted_registry_console_routecertificates: "{{ ('routecertificates' in openshift.hosted.registry.console.keys()) | ternary(openshift.hosted.registry.console.routecertificates, {}) }}" + openshift_hosted_registry_console_routehost: "{{ ('routehost' in openshift.hosted.registry.console.keys()) | ternary(openshift.hosted.registry.console.routehost, False) }}" + openshift_hosted_registry_console_routetermination: "{{ ('routetermination' in openshift.hosted.registry.console.keys()) | ternary(openshift.hosted.registry.console.routetermination, 'passthrough') }}" + + - name: Create directory for registry-console certificates + file: + path: "{{ openshift_master_config_dir }}/registry_console_certificates" + state: directory + owner: root + group: root + mode: 0700 + + - name: Include reencrypt route configuration + include: route/reencrypt.yml + static: no + when: openshift_hosted_registry_console_routetermination == 'reencrypt' + + - name: Include passthrough route configuration + include: route/passthrough.yml + static: no + when: openshift_hosted_registry_console_routetermination == 'passthrough' # When openshift_hosted_manage_registry=true the openshift_hosted # role will create the appropriate route for the docker-registry. # When openshift_hosted_manage_registry=false then this code will # not be run. - - name: fetch the docker-registry route + - name: Fetch the docker-registry route oc_route: - kubeconfig: "{{ openshift_master_config_dir }}/admin.kubeconfig" name: docker-registry namespace: default state: list register: docker_registry_route - - name: Create passthrough route for registry-console + - name: Fetch the registry-console route oc_route: - kubeconfig: "{{ openshift_master_config_dir }}/admin.kubeconfig" name: registry-console namespace: default - service_name: registry-console - state: present - tls_termination: passthrough - register: registry_console_cockpit_kube - - # XXX: Required for items still using command - - name: Create temp directory for kubeconfig - command: mktemp -d /tmp/openshift-ansible-XXXXXX - register: mktemp - changed_when: False - - - set_fact: - openshift_hosted_kubeconfig: "{{ mktemp.stdout }}/admin.kubeconfig" - - - name: Copy the admin client config(s) - command: > - cp {{ openshift_master_config_dir }}/admin.kubeconfig {{ openshift_hosted_kubeconfig }} - changed_when: False + state: list + register: registry_console_route # TODO: Need to fix the origin and enterprise templates so that they both respect IMAGE_PREFIX - name: Deploy registry-console @@ -45,19 +51,68 @@ {% if openshift_cockpit_deployer_version is defined %}-p IMAGE_VERSION="{{ openshift_cockpit_deployer_version }}"{% endif %} -p OPENSHIFT_OAUTH_PROVIDER_URL="{{ openshift.master.public_api_url }}" -p REGISTRY_HOST="{{ docker_registry_route.results[0].spec.host }}" - -p COCKPIT_KUBE_URL="https://{{ registry_console_cockpit_kube.results.results[0].spec.host }}" - --config={{ openshift_hosted_kubeconfig }} - -n default + -p COCKPIT_KUBE_URL="https://{{ registry_console_route.results[0].spec.host }}" + --config={{ openshift_master_config_dir }}/admin.kubeconfig + -n {{ openshift_hosted_registry_console_namespace }} register: deploy_registry_console changed_when: "'already exists' not in deploy_registry_console.stderr" - failed_when: - - "'already exists' not in deploy_registry_console.stderr" - - "deploy_registry_console.rc != 0" + failed_when: "'already exists' not in deploy_registry_console.stderr and deploy_registry_console.rc != 0" - - name: Delete temp directory - file: - name: "{{ mktemp.stdout }}" - state: absent - changed_when: False - # XXX: End required for items still using command + - name: Retrieve registry-console service for the clusterip + oc_service: + namespace: "{{ openshift_hosted_registry_console_namespace }}" + name: registry-console + state: list + register: docker_registry_console_service + + - name: Generate self-signed registry-console certificates + oc_adm_ca_server_cert: + signer_cert: "{{ openshift_master_config_dir }}/ca.crt" + signer_key: "{{ openshift_master_config_dir }}/ca.key" + signer_serial: "{{ openshift_master_config_dir }}/ca.serial.txt" + hostnames: + - "{{ docker_registry_console_service.results.clusterip }}" + - "{{ registry_console_route.results[0].spec.host }}" + cert: "{{ docker_registry_console_cert_path }}" + key: "{{ docker_registry_console_key_path }}" + expire_days: "{{ openshift_hosted_registry_console_cert_expire_days if openshift_version | oo_version_gte_3_5_or_1_5(openshift.common.deployment_type) | bool else omit }}" + when: docker_registry_console_self_signed + + # The certificate file expected inside the registry-console service is + # in .pem format that bundles the certificate(s) and the private key. + - name: Retrieve certificate files to generate certificate bundle + slurp: + src: "{{ item }}" + with_items: > + {%- set files = [ docker_registry_console_cert_path ] %} + {%- if docker_registry_console_cacert is defined %} + {%- set _ = files.append(docker_registry_console_cacert) %} + {%- endif %} + {%- set _ = files.append(docker_registry_console_key_path) %} + {{- files -}} + register: certificate_files + + - name: Generate certificate bundle + copy: + content: "{{ certificate_files.results | map(attribute='content') | map('b64decode') | join('') }}" + dest: "{{ openshift_master_config_dir }}/registry_console_certificates/registry-console.pem" + + - name: Create the secret for the registry-console certificate + oc_secret: + name: registry-console-certificate + namespace: "{{ openshift_hosted_registry_console_namespace }}" + files: + - name: registry-console.cert + path: "{{ openshift_master_config_dir }}/registry_console_certificates/registry-console.pem" + + - name: Mount secret registry console certificates volume + oc_volume: + state: present + namespace: "{{ openshift_hosted_registry_console_namespace }}" + kind: dc + name: registry-console + mount_type: secret + mount_path: "/etc/cockpit/ws-certs.d" + secret_name: registry-console-certificate + vol_name: registry-console-certificate run_once: true diff --git a/roles/cockpit-ui/tasks/route/passthrough.yml b/roles/cockpit-ui/tasks/route/passthrough.yml new file mode 100644 index 00000000000..86e854c0853 --- /dev/null +++ b/roles/cockpit-ui/tasks/route/passthrough.yml @@ -0,0 +1,46 @@ +--- +# We'll generate a self-signed certificate when there is no user-supplied +# certificate +- name: Configure self-signed certificate file paths + set_fact: + docker_registry_console_cert_path: "{{ openshift_master_config_dir }}/registry-console.crt" + docker_registry_console_key_path: "{{ openshift_master_config_dir }}/registry-console.key" + docker_registry_console_cacert_path: "{{ openshift_master_config_dir }}/ca.crt" + docker_registry_console_self_signed: true + when: + - "'certfile' not in openshift_hosted_registry_console_routecertificates" + - "'keyfile' not in openshift_hosted_registry_console_routecertificates" + +# Retrieve user supplied certificate files if they are provided +- when: + - "'certfile' in openshift_hosted_registry_console_routecertificates" + - "'keyfile' in openshift_hosted_registry_console_routecertificates" + block: + - name: Configure provided certificate file paths + set_fact: + docker_registry_console_cert_path: "{{ openshift_master_config_dir }}/registry_console_certificates/{{ openshift_hosted_registry_console_routecertificates['certfile'] | basename }}" + docker_registry_console_key_path: "{{ openshift_master_config_dir }}/registry_console_certificates/{{ openshift_hosted_registry_console_routecertificates['keyfile'] | basename }}" + docker_registry_console_self_signed: false + + # Since we end up bundling the cert, cacert and key in a .pem file, the 'cafile' + # is optional + - name: Configure provided ca certificate file path + set_fact: + docker_registry_console_cacert_path: "{{ openshift_master_config_dir }}/registry_console_certificates/{{ openshift_hosted_registry_console_routecertificates['cafile'] | basename }}" + when: "'cafile' in openshift_hosted_registry_console_routecertificates" + + - name: Retrieve provided certificate files + copy: + backup: True + dest: "{{ openshift_master_config_dir }}/registry_console_certificates/{{ item.value | basename }}" + src: "{{ item.value }}" + when: item.key in ['certfile', 'keyfile', 'cafile'] and item.value + with_dict: "{{ openshift_hosted_registry_console_routecertificates }}" + +- name: Configure a passthrough route for registry-console + oc_route: + name: registry-console + namespace: "{{ openshift_hosted_registry_console_namespace }}" + service_name: registry-console + tls_termination: "{{ openshift_hosted_registry_console_routetermination }}" + host: "{{ openshift_hosted_registry_console_routehost | default(omit, true) }}" diff --git a/roles/cockpit-ui/tasks/route/reencrypt.yml b/roles/cockpit-ui/tasks/route/reencrypt.yml new file mode 100644 index 00000000000..bd81c753f75 --- /dev/null +++ b/roles/cockpit-ui/tasks/route/reencrypt.yml @@ -0,0 +1,38 @@ +--- +- name: Validate route termination configuration + fail: + msg: > + When 'openshift_hosted_registry_console_routetermination' is 'reencrypt', you must + provide certificate files with 'openshift_hosted_registry_console_routecertificates' + when: ('certfile' not in openshift_hosted_registry_console_routecertificates) or + ('keyfile' not in openshift_hosted_registry_console_routecertificates) or + ('cafile' not in openshift_hosted_registry_console_routecertificates) + +- name: Configure self-signed certificate file paths + set_fact: + docker_registry_console_cert_path: "{{ openshift_master_config_dir }}/registry-console.crt" + docker_registry_console_key_path: "{{ openshift_master_config_dir }}/registry-console.key" + docker_registry_console_cacert_path: "{{ openshift_master_config_dir }}/ca.crt" + docker_registry_console_self_signed: true + +- name: Retrieve provided certificate files + copy: + backup: True + dest: "{{ openshift_master_config_dir }}/registry_console_certificates/{{ item.value | basename }}" + src: "{{ item.value }}" + when: item.key in ['certfile', 'keyfile', 'cafile'] and item.value + with_dict: "{{ openshift_hosted_registry_console_routecertificates }}" + +# Encrypt with the provided certificate and provide the dest_cacert for the +# self-signed certificate at the endpoint +- name: Configure a reencrypt route for registry-console + oc_route: + name: registry-console + namespace: "{{ openshift_hosted_registry_console_namespace }}" + service_name: registry-console + tls_termination: "{{ openshift_hosted_registry_console_routetermination }}" + host: "{{ openshift_hosted_registry_console_routehost | default(omit, true) }}" + cert_path: "{{ openshift_master_config_dir }}/registry_console_certificates/{{ openshift_hosted_registry_console_routecertificates['certfile'] | basename }}" + key_path: "{{ openshift_master_config_dir }}/registry_console_certificates/{{ openshift_hosted_registry_console_routecertificates['keyfile'] | basename }}" + cacert_path: "{{ openshift_master_config_dir }}/registry_console_certificates/{{ openshift_hosted_registry_console_routecertificates['cafile'] | basename }}" + dest_cacert_path: "{{ openshift_master_config_dir }}/ca.crt"