From cea1cd428f8dc217b38c249d7f19a3d135c2dcd5 Mon Sep 17 00:00:00 2001 From: David Moreau-Simard Date: Tue, 24 Oct 2017 16:18:19 -0400 Subject: [PATCH] Refactor cockpit-ui setup and add support for SSL This renames the role 'cockpit-ui' to 'openshift_hosted_registry_console' to bring it in line with the other roles related to openshift_hosted. This is a refactor to significantly improve the configurability of the registry console service and route in order to bring it in line with the way we configure docker-registry. Effectively, this adds the ability to select a hostname for the registry console and adds support for securing the registry-console route with a provided SSL certificate either with passthrough or reencrypt termination. We maintain backwards compatibility by keeping the same default which provides a default registry-console hostname and self-signed certificates on a passthrough route. --- .../openshift-cluster/openshift_hosted.yml | 2 +- ... => openshift_hosted_registry_console.yml} | 4 +- roles/cockpit-ui/tasks/main.yml | 63 ---------- .../defaults/main.yml | 1 + .../meta/main.yml | 2 +- .../tasks/main.yml | 118 ++++++++++++++++++ .../tasks/route/passthrough.yml | 46 +++++++ .../tasks/route/reencrypt.yml | 38 ++++++ 8 files changed, 207 insertions(+), 67 deletions(-) rename playbooks/common/openshift-cluster/{cockpit-ui.yml => openshift_hosted_registry_console.yml} (68%) delete mode 100644 roles/cockpit-ui/tasks/main.yml rename roles/{cockpit-ui => openshift_hosted_registry_console}/defaults/main.yml (72%) rename roles/{cockpit-ui => openshift_hosted_registry_console}/meta/main.yml (79%) create mode 100644 roles/openshift_hosted_registry_console/tasks/main.yml create mode 100644 roles/openshift_hosted_registry_console/tasks/route/passthrough.yml create mode 100644 roles/openshift_hosted_registry_console/tasks/route/reencrypt.yml diff --git a/playbooks/common/openshift-cluster/openshift_hosted.yml b/playbooks/common/openshift-cluster/openshift_hosted.yml index c1536eb3622..658398865ee 100644 --- a/playbooks/common/openshift-cluster/openshift_hosted.yml +++ b/playbooks/common/openshift-cluster/openshift_hosted.yml @@ -19,7 +19,7 @@ - include: openshift_hosted_registry.yml -- include: cockpit-ui.yml +- include: openshift_hosted_registry_console.yml - include: openshift_prometheus.yml when: openshift_hosted_prometheus_deploy | default(False) | bool diff --git a/playbooks/common/openshift-cluster/cockpit-ui.yml b/playbooks/common/openshift-cluster/openshift_hosted_registry_console.yml similarity index 68% rename from playbooks/common/openshift-cluster/cockpit-ui.yml rename to playbooks/common/openshift-cluster/openshift_hosted_registry_console.yml index 5ddafdb07e2..43bfca51943 100644 --- a/playbooks/common/openshift-cluster/cockpit-ui.yml +++ b/playbooks/common/openshift-cluster/openshift_hosted_registry_console.yml @@ -1,6 +1,6 @@ --- -- name: Create Hosted Resources - cockpit-ui +- name: Create Hosted Resources - Registry Console (cockpit-ui) hosts: oo_first_master roles: - - role: cockpit-ui + - role: openshift_hosted_registry_console when: ( openshift.common.version_gte_3_3_or_1_3 | bool ) and ( openshift_hosted_manage_registry | default(true) | bool ) and not (openshift.docker.hosted_registry_insecure | default(false) | bool) diff --git a/roles/cockpit-ui/tasks/main.yml b/roles/cockpit-ui/tasks/main.yml deleted file mode 100644 index 244e2cc4138..00000000000 --- a/roles/cockpit-ui/tasks/main.yml +++ /dev/null @@ -1,63 +0,0 @@ ---- -- block: - - # 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 - 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 - 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 - - # TODO: Need to fix the origin and enterprise templates so that they both respect IMAGE_PREFIX - - name: Deploy registry-console - command: > - {{ openshift.common.client_binary }} new-app --template=registry-console - {% if openshift_cockpit_deployer_prefix is defined %}-p IMAGE_PREFIX="{{ openshift_cockpit_deployer_prefix }}"{% endif %} - {% 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 - 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" - - - name: Delete temp directory - file: - name: "{{ mktemp.stdout }}" - state: absent - changed_when: False - # XXX: End required for items still using command - run_once: true diff --git a/roles/cockpit-ui/defaults/main.yml b/roles/openshift_hosted_registry_console/defaults/main.yml similarity index 72% rename from roles/cockpit-ui/defaults/main.yml rename to roles/openshift_hosted_registry_console/defaults/main.yml index b1696f1b88a..c31e409b998 100644 --- a/roles/cockpit-ui/defaults/main.yml +++ b/roles/openshift_hosted_registry_console/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/meta/main.yml b/roles/openshift_hosted_registry_console/meta/main.yml similarity index 79% rename from roles/cockpit-ui/meta/main.yml rename to roles/openshift_hosted_registry_console/meta/main.yml index 4d619fff635..b10d83c7908 100644 --- a/roles/cockpit-ui/meta/main.yml +++ b/roles/openshift_hosted_registry_console/meta/main.yml @@ -1,7 +1,7 @@ --- galaxy_info: author: Samuel Munilla - description: Deploy and Enable cockpit-ui + description: Deploy and Enable Registry Console (cockpit-ui) company: Red Hat, Inc. license: Apache License, Version 2.0 min_ansible_version: 2.1 diff --git a/roles/openshift_hosted_registry_console/tasks/main.yml b/roles/openshift_hosted_registry_console/tasks/main.yml new file mode 100644 index 00000000000..4729f25f52c --- /dev/null +++ b/roles/openshift_hosted_registry_console/tasks/main.yml @@ -0,0 +1,118 @@ +--- +- 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 + oc_route: + name: docker-registry + namespace: default + state: list + register: docker_registry_route + + - name: Fetch the registry-console route + oc_route: + name: registry-console + namespace: default + 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 + command: > + {{ openshift.common.client_binary }} new-app --template=registry-console + {% if openshift_cockpit_deployer_prefix is defined %}-p IMAGE_PREFIX="{{ openshift_cockpit_deployer_prefix }}"{% endif %} + {% 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_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 and deploy_registry_console.rc != 0" + + - 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/openshift_hosted_registry_console/tasks/route/passthrough.yml b/roles/openshift_hosted_registry_console/tasks/route/passthrough.yml new file mode 100644 index 00000000000..86e854c0853 --- /dev/null +++ b/roles/openshift_hosted_registry_console/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/openshift_hosted_registry_console/tasks/route/reencrypt.yml b/roles/openshift_hosted_registry_console/tasks/route/reencrypt.yml new file mode 100644 index 00000000000..bd81c753f75 --- /dev/null +++ b/roles/openshift_hosted_registry_console/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"