diff --git a/examples/migrate/migrate-platform-certificates-to-certmanager-inventory-EXAMPLE.yml b/examples/migrate/migrate-platform-certificates-to-certmanager-inventory-EXAMPLE.yml index 15c4d4782..d732f9043 100644 --- a/examples/migrate/migrate-platform-certificates-to-certmanager-inventory-EXAMPLE.yml +++ b/examples/migrate/migrate-platform-certificates-to-certmanager-inventory-EXAMPLE.yml @@ -1,6 +1,6 @@ --- # -# Copyright (c) 2021-2022 Wind River Systems, Inc. +# Copyright (c) 2021-2023 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -32,13 +32,15 @@ # # Please make sure that you use a system_root_ca_cert and system_local_ca_cert certificate # with a long duration. The playbook will fail if any of these CA certificates expire in -# less than 3 years. +# less than the default expected values in min years: +# - For RCA, is 3 years; +# - For ICA, is 1 year. # # If you wish to use a different value for CA duration you can override -# it by setting a different value to validation parameter ca_duration: +# it by setting a different value to validation parameters rca_duration/ica_duration. # Example: -# ca_duration: 2 -# Notice that ca_duration is applied to both system_root_ca_cert and system_local_ca_cert +# 'rca_duration: 2' will result in the playbook only accepting RCAs expiring 2 or more +# years from now. # # Please also make sure that duration and renewBefore are sensible values # considering the system_local_ca_cert remaining duration. @@ -57,11 +59,13 @@ all: # Note: system_local_ca_cert and system_root_ca_cert must be the same for that configuration. system_local_ca_cert: system_local_ca_key: - # the ca_duration parameter is optional. If not specified, it defaults to 3. - # It represents the number of years for the CA certificates validity check. + # the ica_duration/rca_duration parameters are optional. If not specified, it defaults to 3 + # for RCA and 1 for ICA. + # It represents the number of years for the CA certificates expiration validity check. # It is not recommended to use short values for this parameter. - # It applies to both system_local_ca_cert and the system_local_ca_cert certificates. - ca_duration: 3 + # rca_duration: 3 + # ica_duration: 1 + children: # This will be applied to all online subclouds # Use the below example in hosts to override particulars for a subcloud such as passwords diff --git a/playbookconfig/src/playbooks/migrate_platform_certificates_to_certmanager.yml b/playbookconfig/src/playbooks/migrate_platform_certificates_to_certmanager.yml index 617f56b0e..dbd2cf523 100644 --- a/playbookconfig/src/playbooks/migrate_platform_certificates_to_certmanager.yml +++ b/playbookconfig/src/playbooks/migrate_platform_certificates_to_certmanager.yml @@ -83,12 +83,9 @@ - block: - name: Install certificates as system Trusted CA certificates include_role: - name: common/install-trusted-ca - with_items: - - { name: system_local_ca_cert, content: "{{ system_local_ca_cert }}" } - - { name: system_root_ca_cert, content: "{{ system_root_ca_cert }}" } - loop_control: - label: "{{ item.name }}" + name: common/verify-and-install-system-local-ca-certs + vars: + - install_rca: true - name: Restart kube-apiserver to pick the new certificates include_role: diff --git a/playbookconfig/src/playbooks/roles/bootstrap/install-platform-certificates/tasks/retrieve-system-local-ca-data.yml b/playbookconfig/src/playbooks/roles/bootstrap/install-platform-certificates/tasks/retrieve-system-local-ca-data.yml index 4d2ad2b29..d75a5a384 100644 --- a/playbookconfig/src/playbooks/roles/bootstrap/install-platform-certificates/tasks/retrieve-system-local-ca-data.yml +++ b/playbookconfig/src/playbooks/roles/bootstrap/install-platform-certificates/tasks/retrieve-system-local-ca-data.yml @@ -92,10 +92,8 @@ - name: Install system_root_ca_cert as Trusted CA include_role: - name: common/install-trusted-ca - with_items: - - { name: system_root_ca_cert, content: "{{ system_root_ca_cert }}" } - loop_control: - label: "{{ item.name }}" + name: common/verify-and-install-system-local-ca-certs + vars: + - install_rca: true when: - install_rca_as_trusted diff --git a/playbookconfig/src/playbooks/roles/bootstrap/install-platform-certificates/vars/main.yml b/playbookconfig/src/playbooks/roles/bootstrap/install-platform-certificates/vars/main.yml index 0c1b7dff1..53136a585 100644 --- a/playbookconfig/src/playbooks/roles/bootstrap/install-platform-certificates/vars/main.yml +++ b/playbookconfig/src/playbooks/roles/bootstrap/install-platform-certificates/vars/main.yml @@ -7,7 +7,6 @@ cert_manager_spec_file: /tmp/platform_certificates.yaml -ca_duration: 3 system_platform_certificate: dns_domain: starlingx.local duration: 2160h # 90d diff --git a/playbookconfig/src/playbooks/roles/bootstrap/validate-config/tasks/main.yml b/playbookconfig/src/playbooks/roles/bootstrap/validate-config/tasks/main.yml index 2c689f9a7..a24a52a4d 100644 --- a/playbookconfig/src/playbooks/roles/bootstrap/validate-config/tasks/main.yml +++ b/playbookconfig/src/playbooks/roles/bootstrap/validate-config/tasks/main.yml @@ -906,7 +906,7 @@ msg: "system_local_ca_key file not found. ({{ system_local_ca_key }})" when: (system_local_ca_key | length > 0) and not (system_local_ca_key is file) - - name: Encode the user provided files cert/key files + - name: Encode the user provided cert/key files block: - name: Encode system_root_ca_cert shell: cat "{{ system_root_ca_cert }}" | base64 -w0 @@ -926,12 +926,19 @@ system_local_ca_cert_file: "{{ system_local_ca_cert }}" system_local_ca_key_file: "{{ system_local_ca_key }}" - # TODO (mdecastr): Generalize cert verification for trusted CAs and include in here - set_fact: system_root_ca_cert: "{{ root_ca_cert_output.stdout }}" system_local_ca_cert: "{{ local_ca_cert_output.stdout }}" system_local_ca_key: "{{ local_ca_key_output.stdout }}" system_local_ca_overrides: true + + - name: Verify 'system-local-ca' certs + include_role: + name: common/verify-and-install-system-local-ca-certs + vars: + - install_rca: false + - enforce_ica: true + when: system_local_ca_cert | length > 0 when: mode != 'restore' diff --git a/playbookconfig/src/playbooks/roles/common/install-trusted-ca/tasks/main.yml b/playbookconfig/src/playbooks/roles/common/install-trusted-ca/tasks/main.yml deleted file mode 100644 index db7e0b268..000000000 --- a/playbookconfig/src/playbooks/roles/common/install-trusted-ca/tasks/main.yml +++ /dev/null @@ -1,212 +0,0 @@ ---- -# -# Copyright (c) 2021-2023 Wind River Systems, Inc. -# -# SPDX-License-Identifier: Apache-2.0 -# -# These tasks provide the functionality to validate ICA duration and -# install it as a platform Trusted CA. -# -- name: Create root pem temporary file - tempfile: - state: file - prefix: root_ - suffix: .pem - path: /tmp/ - register: root_ca_file - -- name: Create ca pem temporary file - tempfile: - state: file - prefix: ca_ - suffix: .pem - path: /tmp/ - register: local_ca_file - -- name: Save {{ item.name }} certificate to a file - copy: - dest: "{{ local_ca_file.path }}" - content: "{{ item.content | b64decode }}" - mode: 0640 - -- block: - - name: Save system_root_ca_cert to a file - copy: - dest: "{{ root_ca_file.path }}" - content: "{{ system_root_ca_cert | b64decode }}" - mode: 0640 - - - name: Check if system_local_ca_cert is signed by system_root_ca_cert or self-signed - command: openssl verify -verbose -CAfile {{ root_ca_file.path }} {{ local_ca_file.path }} - register: ca_verification - # failed_when as false in order to print a better error msg in the task below - failed_when: false - - - name: Fail when system_local_ca_cert is not signed by system_root_ca_cert or self-signed - fail: - msg: | - The system_local_ca_cert provided is not signed by - system_root_ca_cert provided or self-signed. - Please review your inventory parameters. - when: ca_verification.rc | int != 0 - when: item.name == 'system_local_ca_cert' - -- name: Get CA information from certificate - shell: | - openssl x509 -in {{ local_ca_file.path }} -text -noout | grep "CA:" - register: is_ca - -- name: Fail when certificate specified is not an actual CA certificate - fail: - msg: The {{ item.name }} certificate provided is not a CA certificate (CA:FALSE) - when: "'CA:TRUE' not in is_ca.stdout" - -- name: Get years for CA duration validation - set_fact: - ca_duration: "{{ ca_duration if ca_duration is defined else 3 }}" - -- name: Check that CA certificate remaining duration is longer than {{ ca_duration }} years - shell: | - expiration_date=$(cat {{ local_ca_file.path }} | openssl x509 -noout -enddate | cut -d'=' -f2) - expiration_date_timestamp=$(date -d "${expiration_date}" +%s) - date_5years_from_now_timestamp=$(date -d "+{{ ca_duration }} years" +%s) - time_left_ica=$(expr $expiration_date_timestamp - $date_5years_from_now_timestamp) - echo $time_left_ica - register: ica_time_left - -- name: Fail when CA certificate remaining duration is shorter than {{ ca_duration }} years - fail: - msg: >- - The remaining duration for the {{ item.name }} certificate specified - is less than {{ ca_duration }} years. - Please use a certificate with a longer validity. - when: ica_time_left.stdout | int < 0 - -# ignore_alarms flag can be set to avoid waiting. Defaults to false. -- name: Initialize flag ignore_alarms - set_fact: - ignore_alarms: "{{ false if ignore_alarms is not defined else ignore_alarms | bool }}" - -- name: Verify if there are 250.001 (config out-of-date) alarms before installing certificate - block: - - name: Check if an 250.001 alarm exists and wait it to be cleared - shell: | - source /etc/platform/openrc; - fm alarm-list --query alarm_id=250.001 - register: alarm_subcloud - retries: 10 - delay: 20 - until: alarm_subcloud.stdout == "" - failed_when: false - - - name: Fail when the alarm remains - fail: - msg: >- - Timed out waiting 250.001 alarm to clear out. - when: alarm_subcloud.stdout != "" - - - name: Register stat of .config_applied file - stat: - path: /etc/platform/.config_applied - register: prev_config_applied_stat - when: not ignore_alarms - -- name: Install {{ item.name }} certificate as a Trusted CA certificate - shell: >- - source /etc/platform/openrc && - system certificate-install -m ssl_ca {{ local_ca_file.path }} - register: install_cert_output - until: install_cert_output is not failed - retries: 3 - delay: 60 - -- name: Register if a new certificate was installed - set_fact: - new_cert_installed: "{{ true if (install_cert_output is search('uuid') and - install_cert_output is search('certtype') and - install_cert_output is search('signature') and - install_cert_output is search('start_date') and - install_cert_output is search('expiry_date') and - install_cert_output is search('subject')) - else false }}" - -- name: Delete temporary .pem files - file: - path: "{{ file_item }}" - state: absent - with_items: - - "{{ local_ca_file.path }}" - - "{{ root_ca_file.path }}" - loop_control: - loop_var: file_item - become: yes - -# If a new trusted CA is installed, sysinv conductor will apply -# platform::config::runtime puppet manifest. This will cause the -# current config to change. We will monitor it through the file -# .config_applied, which is created/changed when a manifest is -# applied. -- name: Wait while the new config is applied by puppet - block: - - name: Initialize fail control variable - set_fact: - puppet_config_apply_failed: false - - # If the .config_applied file doesn't exist, we wait for it to be created. - - block: - - name: Wait for .config_applied file to be created - stat: - path: /etc/platform/.config_applied - register: current_config_applied_stat - until: current_config_applied_stat.stat.exists - retries: 10 - delay: 20 - failed_when: false - - - name: Set fail control variable - set_fact: - puppet_config_apply_failed: true - when: not current_config_applied_stat.stat.exists - when: not prev_config_applied_stat.stat.exists - - # If the .config_applied file exists, we wait for it to change. - - block: - - name: Wait for .config_applied file stat to change - stat: - path: /etc/platform/.config_applied - register: current_config_applied_stat - until: current_config_applied_stat.stat.checksum != prev_config_applied_stat.stat.checksum - retries: 10 - delay: 20 - failed_when: false - - - name: Set fail control variable - set_fact: - puppet_config_apply_failed: true - when: current_config_applied_stat.stat.checksum == prev_config_applied_stat.stat.checksum - when: prev_config_applied_stat.stat.exists - - - name: Fail when the manifest apply times out - fail: - msg: >- - Timed out applying puppet runtime manifest. Check sysinv and puppet logs - for more information and solve any 250.001 alarms before retrying. - when: puppet_config_apply_failed - - - name: Check if an 250.001 alarm was raised and wait it to be cleared - shell: | - source /etc/platform/openrc; - fm alarm-list --query alarm_id=250.001 - register: alarm_subcloud - retries: 5 - delay: 20 - until: alarm_subcloud.stdout == "" - failed_when: false - - - name: Fail when the alarm remains - fail: - msg: >- - Timed out waiting 250.001 alarm to clear out. Check sysinv and puppet logs - for more information and solve any 250.001 alarms before retrying. - when: alarm_subcloud.stdout != "" - when: new_cert_installed and not ignore_alarms diff --git a/playbookconfig/src/playbooks/roles/common/send-ca-cert-to-subcloud/tasks/main.yml b/playbookconfig/src/playbooks/roles/common/send-ca-cert-to-subcloud/tasks/main.yml index 7f10d69eb..f4d76fab8 100644 --- a/playbookconfig/src/playbooks/roles/common/send-ca-cert-to-subcloud/tasks/main.yml +++ b/playbookconfig/src/playbooks/roles/common/send-ca-cert-to-subcloud/tasks/main.yml @@ -152,9 +152,7 @@ - block: - name: Install new CA certificate (Subcloud) include_role: - name: common/install-trusted-ca - with_items: - - { name: system_root_ca_cert, content: "{{ system_root_ca_cert }}" } - loop_control: - label: "{{ item.name }}" + name: common/verify-and-install-system-local-ca-certs + vars: + - install_rca: true when: not ca_send_from_bootstrap diff --git a/playbookconfig/src/playbooks/roles/common/verify-and-install-system-local-ca-certs/tasks/cert-content-requirements-verification.yml b/playbookconfig/src/playbooks/roles/common/verify-and-install-system-local-ca-certs/tasks/cert-content-requirements-verification.yml new file mode 100644 index 000000000..5322d9793 --- /dev/null +++ b/playbookconfig/src/playbooks/roles/common/verify-and-install-system-local-ca-certs/tasks/cert-content-requirements-verification.yml @@ -0,0 +1,57 @@ +--- +# +# Copyright (c) 2023 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Task that receives an RCA/ICA certs and verifies the requirements +# for it to be used as local issuer for the platform certificates. +# + +- name: Fail if pem stream is undefined + fail: + msg: Variable cert_req_pem_stream must be defined for this task. + when: cert_req_pem_stream is not defined + +- name: Get CA information from certificate + shell: | + echo "{{ cert_req_pem_stream }}" | openssl x509 -text -noout | grep "CA:" + register: is_ca + +- name: Fail when certificate is not a CA certificate + fail: + msg: One of the certificates provided for system-local-ca is not a CA certificate. + when: "'CA:TRUE' not in is_ca.stdout" + +- name: Verify if certificate is a root certificate + shell: >- + openssl verify -verbose -no-CApath -CAfile + <(echo "{{ cert_req_pem_stream }}") <(echo "{{ cert_req_pem_stream }}") + register: openssl_return + failed_when: false + +- name: Assume RCA if verification succeeds + set_fact: + ca_duration: "{{ rca_duration if rca_duration is defined else def_rca_duration }}" + when: openssl_return.rc == 0 + +- name: Assume ICA if verification fails + set_fact: + ca_duration: "{{ ica_duration if ica_duration is defined else def_ica_duration }}" + when: openssl_return.rc != 0 + +- name: Check that CA certificate remaining duration is longer than {{ ca_duration }} years + shell: | + expiration_date=$(echo "{{ cert_req_pem_stream }}" | openssl x509 -noout -enddate | cut -d'=' -f2) + expiration_date_timestamp=$(date -d "${expiration_date}" +%s) + min_date_from_now_timestamp=$(date -d "+{{ ca_duration }} years" +%s) + time_left_ca=$(expr $expiration_date_timestamp - $min_date_from_now_timestamp) + echo $time_left_ca + register: ca_time_left + +- name: Fail when CA certificate remaining duration is shorter than {{ ca_duration }} years + fail: + msg: >- + The remaining duration for one of the certificates specified for system-local-ca + is less than {{ ca_duration }} years. Please use a certificate with a longer validity. + when: ca_time_left.stdout | int < 0 diff --git a/playbookconfig/src/playbooks/roles/common/verify-and-install-system-local-ca-certs/tasks/ica-individual-verification.yml b/playbookconfig/src/playbooks/roles/common/verify-and-install-system-local-ca-certs/tasks/ica-individual-verification.yml new file mode 100644 index 000000000..172c89ce0 --- /dev/null +++ b/playbookconfig/src/playbooks/roles/common/verify-and-install-system-local-ca-certs/tasks/ica-individual-verification.yml @@ -0,0 +1,68 @@ +--- +# +# Copyright (c) 2023 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Subtask designed to be executed in a loop for verifying an ICA +# bundle looking at each individual certificate. +# Assumes that used variable are set in the calling task. +# + +- name: Retrieve the certificate in the end of the chain (first read from the file) + command: openssl x509 -in "{{ aux_ca_file.path }}" + register: ica_pem_cert + +- name: Get a stream from the auxiliar file without the certificate being read + shell: >- + { openssl x509 >/dev/null && cat; } < "{{ aux_ca_file.path }}" + register: cert_stream + become: yes + +- name: Overwrite auxiliar file with remaining ICAs (minus cert currently being checked) + copy: + content: "{{ cert_stream.stdout }}" + dest: "{{ aux_ca_file.path }}" + mode: 0640 + owner: root + group: root + become: yes + +- name: Assign ICA stream to variable + set_fact: + cert_req_pem_stream: "{{ ica_pem_cert.stdout }}" + +- name: Verify ICA certificate content requirements + include_tasks: cert-content-requirements-verification.yml + +- block: + - name: Verify if the ICA is signed by the next CA in the bundle + shell: >- + openssl verify -verbose -no-CApath -no-CAfile -partial_chain -trusted + "{{ aux_ca_file.path }}" <(echo "{{ cert_req_pem_stream }}") + register: openssl_return + failed_when: false + + - name: Fail the ICA certificate isn't signed by the next CA in the bundle + fail: + msg: >- + Failure while verifying system_local_ca ICA chain. Verify the certificates in the + files provided. Error "{{ openssl_return.rc }}": "{{ openssl_return.stdout }}". + when: openssl_return.rc !=0 + when: ica_bundle_cert_remaining | int > 0 + +- block: + - name: Verify if the last certificate is signed by the RCA + shell: >- + openssl verify -verbose -no-CApath -CAfile + "{{ system_local_ca_rca.path }}" <(echo "{{ cert_req_pem_stream }}") + register: openssl_return + failed_when: false + + - name: Fail the certificate isn't signed by the RCA + fail: + msg: >- + Failure while verifying system_local_ca RCA/ICA chain. Verify the certificates + in the files provided. Error "{{ openssl_return.rc }}": "{{ openssl_return.stdout }}". + when: openssl_return.rc !=0 + when: ica_bundle_cert_remaining | int == 0 diff --git a/playbookconfig/src/playbooks/roles/common/verify-and-install-system-local-ca-certs/tasks/main.yml b/playbookconfig/src/playbooks/roles/common/verify-and-install-system-local-ca-certs/tasks/main.yml new file mode 100644 index 000000000..cfabdf55c --- /dev/null +++ b/playbookconfig/src/playbooks/roles/common/verify-and-install-system-local-ca-certs/tasks/main.yml @@ -0,0 +1,209 @@ +--- +# +# Copyright (c) 2021-2023 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +# These tasks provide the functionality to validate CA certificates and +# to install Root CA certificates for the local platform issuer: +# system_root_ca_cert - RCA +# system_local_ca_cert - ICA issued by 'system_root_ca_cert' +# install_rca - If true, RCA is installed as trusted +# enforce_ica - If true, a RCA in the top of the ICA file is not allowed + +- name: Verify if system_local_ca_cert and system_local_ca_key match + shell: >- + diff <(echo "{{ system_local_ca_cert | b64decode }}" | openssl x509 -noout -modulus) + <(echo "{{ system_local_ca_key | b64decode }}" | openssl rsa -noout -modulus) + register: diff_return + failed_when: false + +- name: Fail if system_local_ca_cert and system_local_ca_key doesn't match + fail: + msg: system_local_ca_cert and system_local_ca_key should be a TLS cert/key pair. + when: diff_return.stdout != "" + +- name: Create local CA pem temporary file + tempfile: + state: file + prefix: ca_ + suffix: .pem + path: /tmp/ + register: local_ca_file + +- name: Create root CA pem temporary file + tempfile: + state: file + prefix: root_ + suffix: .pem + path: /tmp/ + register: root_ca_file + +- name: Save system_local_ca_cert certificate to a file + copy: + dest: "{{ local_ca_file.path }}" + content: "{{ system_local_ca_cert | b64decode }}" + mode: 0640 + owner: root + group: root + become: yes + +- name: Save system_root_ca_cert to a file + copy: + dest: "{{ root_ca_file.path }}" + content: "{{ system_root_ca_cert | b64decode }}" + mode: 0640 + owner: root + group: root + become: yes + +- name: Set temporary files to required variables + set_fact: + system_local_ca_rca: "{{ root_ca_file }}" + system_local_ca_ica: "{{ local_ca_file }}" + +- name: Verify RCA/ICA certificates + include_tasks: verify-system-local-ca-certificates.yml + +- name: Install RCA if required + block: + # ignore_alarms flag can be set to avoid waiting. Defaults to false. + - name: Initialize flag ignore_alarms + set_fact: + ignore_alarms: "{{ false if ignore_alarms is not defined else ignore_alarms | bool }}" + + - name: Verify if there are 250.001 (config out-of-date) alarms before installing certificate + block: + - name: Check if an 250.001 alarm exists and wait it to be cleared + shell: | + source /etc/platform/openrc; + fm alarm-list --query alarm_id=250.001 + register: alarm_subcloud + retries: 10 + delay: 20 + until: alarm_subcloud.stdout == "" + failed_when: false + + - name: Fail when the alarm remains + fail: + msg: >- + Timed out waiting 250.001 alarm to clear out. + when: alarm_subcloud.stdout != "" + + - name: Register stat of .config_applied file + stat: + path: /etc/platform/.config_applied + register: prev_config_applied_stat + when: not ignore_alarms + + - name: Install RCA as Trusted CA + block: + - name: Install system_root_ca_cert certificate as a Trusted CA certificate + shell: >- + source /etc/platform/openrc && + system certificate-install -m ssl_ca "{{ root_ca_file.path }}" + register: install_cert_output + until: install_cert_output is not failed + retries: 3 + delay: 60 + + - name: Register if a new certificate was installed + set_fact: + new_cert_installed: "{{ true if (install_cert_output is search('uuid') and + install_cert_output is search('certtype') and + install_cert_output is search('signature') and + install_cert_output is search('start_date') and + install_cert_output is search('expiry_date') and + install_cert_output is search('subject')) + else false }}" + error_certs_not_installed: "{{ true if install_cert_output is + search('WARNING: Some certificates were not installed.') + else false }}" + + - name: Fail if some certificates aren't installed + fail: + msg: "{{ install_cert_output.stdout }}" + when: error_certs_not_installed + + when: install_rca + +- name: Delete temporary .pem files + file: + path: "{{ file_item }}" + state: absent + with_items: + - "{{ local_ca_file.path }}" + - "{{ root_ca_file.path }}" + loop_control: + loop_var: file_item + become: yes + +# If a new trusted CA is installed, sysinv conductor will apply +# platform::config::runtime puppet manifest. This will cause the +# current config to change. We will monitor it through the file +# .config_applied, which is created/changed when a manifest is +# applied. +- name: Wait while the new config is applied by puppet + block: + - name: Initialize fail control variable + set_fact: + puppet_config_apply_failed: false + + # If the .config_applied file doesn't exist, we wait for it to be created. + - block: + - name: Wait for .config_applied file to be created + stat: + path: /etc/platform/.config_applied + register: current_config_applied_stat + until: current_config_applied_stat.stat.exists + retries: 10 + delay: 20 + failed_when: false + + - name: Set fail control variable + set_fact: + puppet_config_apply_failed: true + when: not current_config_applied_stat.stat.exists + when: not prev_config_applied_stat.stat.exists + + # If the .config_applied file exists, we wait for it to change. + - block: + - name: Wait for .config_applied file stat to change + stat: + path: /etc/platform/.config_applied + register: current_config_applied_stat + until: current_config_applied_stat.stat.checksum != prev_config_applied_stat.stat.checksum + retries: 10 + delay: 20 + failed_when: false + + - name: Set fail control variable + set_fact: + puppet_config_apply_failed: true + when: current_config_applied_stat.stat.checksum == prev_config_applied_stat.stat.checksum + when: prev_config_applied_stat.stat.exists + + - name: Fail when the manifest apply times out + fail: + msg: >- + Timed out applying puppet runtime manifest. Check sysinv and puppet logs + for more information and solve any 250.001 alarms before retrying. + when: puppet_config_apply_failed + + - name: Check if an 250.001 alarm was raised and wait it to be cleared + shell: | + source /etc/platform/openrc; + fm alarm-list --query alarm_id=250.001 + register: alarm_subcloud + retries: 5 + delay: 20 + until: alarm_subcloud.stdout == "" + failed_when: false + + - name: Fail when the alarm remains + fail: + msg: >- + Timed out waiting 250.001 alarm to clear out. Check sysinv and puppet logs + for more information and solve any 250.001 alarms before retrying. + when: alarm_subcloud.stdout != "" + when: new_cert_installed and not ignore_alarms diff --git a/playbookconfig/src/playbooks/roles/common/verify-and-install-system-local-ca-certs/tasks/verify-system-local-ca-certificates.yml b/playbookconfig/src/playbooks/roles/common/verify-and-install-system-local-ca-certs/tasks/verify-system-local-ca-certificates.yml new file mode 100644 index 000000000..89da981f5 --- /dev/null +++ b/playbookconfig/src/playbooks/roles/common/verify-and-install-system-local-ca-certs/tasks/verify-system-local-ca-certificates.yml @@ -0,0 +1,114 @@ +--- +# +# Copyright (c) 2023 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +# Task that receives an ICA bundle file and RCA file and verifies the +# chain consistency and other requirements for it to be used as local +# issuer for the platform certificates, such as certificate duration. +# Optionally, the RCA can be used as RCA and ICA bundle (for test lab +# scenarios). +# + +- name: Retrieve the number of certificates in RCA file + shell: expr $(openssl storeutl -noout -certs "{{ system_local_ca_rca.path }}" | wc -l) - 1 + register: rca_certs_number + +- name: Fail if there isn't exactly one certificate in the RCA file + fail: + msg: >- + RCA file for system_local_ca should contain only the CA certificate at the + top of the trusted chain (Root CA). + when: rca_certs_number.stdout | int != 1 + +- name: Get RCA pem contents + command: openssl x509 -in "{{ system_local_ca_rca.path }}" + register: rca_pem_cert + +- name: Set variable with RCA content + set_fact: + cert_req_pem_stream: "{{ rca_pem_cert.stdout }}" + +- name: Verify RCA certificate content requirements + include_tasks: cert-content-requirements-verification.yml + +- name: Verify if certificate is RCA + shell: >- + openssl verify -verbose -no-CApath -CAfile + <(echo "{{ cert_req_pem_stream }}") <(echo "{{ cert_req_pem_stream }}") + register: openssl_return + failed_when: false + +- name: Fail if certificate is not a RCA + fail: + msg: >- + RCA file should contain a Root CA certificate. + when: openssl_return.rc != 0 + +- name: Retrieve the number of certificates in ICA file + shell: expr $(openssl storeutl -noout -certs "{{ system_local_ca_ica.path }}" | wc -l) - 1 + register: ica_certs_number + +- name: Fail if there isn't one or more certificates in the ICA file + fail: + msg: >- + ICA file for system_local_ca should have at least one CA certificate. + when: ica_certs_number.stdout | int == 0 + +- name: Create pem temporary file for manipulating the certificates + tempfile: + state: file + prefix: bundle_ + suffix: .pem + path: /tmp/ + register: aux_ca_file + +- name: Copy ICA file contents to auxiliar file + copy: + src: "{{ system_local_ca_ica.path }}" + dest: "{{ aux_ca_file.path }}" + mode: 0640 + owner: root + group: root + become: yes + +- name: Verification for ICA enforced mode + block: + - name: Retrieve the certificate in the end of the ICA chain (first read from the file) + command: openssl x509 -in "{{ aux_ca_file.path }}" + register: ica_pem_cert + + - name: Assign ICA stream to variable + set_fact: + cert_pem_stream: "{{ ica_pem_cert.stdout }}" + + - name: Verify if certificate is a RCA + shell: >- + openssl verify -verbose -no-CApath -CAfile + <(echo "{{ cert_pem_stream }}") <(echo "{{ cert_pem_stream }}") + register: openssl_return + failed_when: false + + - name: Fail if certificate is a RCA + fail: + msg: >- + ICA file must contain a proper Intermediate CA certificate (not a Root CA). + when: openssl_return.rc == 0 + when: enforce_ica + +- name: Set counter for ICA bundle verification + set_fact: + ica_cert_loop_executions: "{{ ica_certs_number.stdout | int }}" + +- name: Loop over the ICA bundle to verify the certificates + include_tasks: ica-individual-verification.yml + with_sequence: start="{{ ica_cert_loop_executions | int - 1 }}" end=0 stride=-1 + loop_control: + loop_var: ica_bundle_cert_remaining + +- name: Remove the auxiliar file + file: + path: "{{ aux_ca_file.path }}" + state: absent + become: yes diff --git a/playbookconfig/src/playbooks/roles/common/verify-and-install-system-local-ca-certs/vars/main.yml b/playbookconfig/src/playbooks/roles/common/verify-and-install-system-local-ca-certs/vars/main.yml new file mode 100644 index 000000000..b116fb8fa --- /dev/null +++ b/playbookconfig/src/playbooks/roles/common/verify-and-install-system-local-ca-certs/vars/main.yml @@ -0,0 +1,13 @@ +--- +# +# Copyright (c) 2023 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +install_rca: false +enforce_ica: false +new_cert_installed: false +error_certs_not_installed: false +def_rca_duration: 3 +def_ica_duration: 3 diff --git a/playbookconfig/src/playbooks/roles/migrate-platform-certificates-to-certmanager/migrate-certificates/tasks/main.yml b/playbookconfig/src/playbooks/roles/migrate-platform-certificates-to-certmanager/migrate-certificates/tasks/main.yml index 5de7f0780..22664ddd3 100644 --- a/playbookconfig/src/playbooks/roles/migrate-platform-certificates-to-certmanager/migrate-certificates/tasks/main.yml +++ b/playbookconfig/src/playbooks/roles/migrate-platform-certificates-to-certmanager/migrate-certificates/tasks/main.yml @@ -142,12 +142,9 @@ - name: Install certificates as system Trusted CA certificates include_role: - name: common/install-trusted-ca - with_items: - - { name: system_local_ca_cert, content: "{{ system_local_ca_cert }}" } - - { name: system_root_ca_cert, content: "{{ system_root_ca_cert }}" } - loop_control: - label: "{{ item.name }}" + name: common/verify-and-install-system-local-ca-certs + vars: + - install_rca: true - name: Restart kube-apiserver to pick the new certificates include_role: