From d9451f49f36f6851f2d10cc2abe31e3fdfd84ab6 Mon Sep 17 00:00:00 2001 From: Matt Crees Date: Mon, 24 Apr 2023 17:11:00 +0100 Subject: [PATCH] Add support for checking Octavia cert expiration Adds a flag ``kolla-ansible octavia-certificates --check-expiry `` to the ``octavia-certificates`` command to check if the certificates will expire within a given number of days. Change-Id: I869b8afd85fe282d823ecf3593aa22f94a61b2a0 --- .../octavia-certificates/defaults/main.yml | 3 + .../tasks/check_expiry.yml | 24 +++++++ .../roles/octavia-certificates/tasks/main.yml | 65 ++++++++++--------- doc/source/reference/networking/octavia.rst | 10 +++ ...k-certificate-expiry-9a80a68cf31cbba4.yaml | 7 ++ tests/run.yml | 2 + tests/test-octavia.sh | 9 +++ tools/kolla-ansible | 12 +++- 8 files changed, 102 insertions(+), 30 deletions(-) create mode 100644 ansible/roles/octavia-certificates/tasks/check_expiry.yml create mode 100644 releasenotes/notes/octavia-check-certificate-expiry-9a80a68cf31cbba4.yaml diff --git a/ansible/roles/octavia-certificates/defaults/main.yml b/ansible/roles/octavia-certificates/defaults/main.yml index 67fe9085af..2061dbe438 100644 --- a/ansible/roles/octavia-certificates/defaults/main.yml +++ b/ansible/roles/octavia-certificates/defaults/main.yml @@ -43,3 +43,6 @@ octavia_certs_client_req_organizational_unit: "{{ octavia_certs_organizational_u # NOTE(yoctozepto): This should ideally be per controller, i.e. controller # generates its key&CSR and this CA signs it. octavia_certs_client_req_common_name: client.example.org + +# Used with command `kolla-ansible octavia-certificates --check-expiry `. +octavia_certs_check_expiry: "no" diff --git a/ansible/roles/octavia-certificates/tasks/check_expiry.yml b/ansible/roles/octavia-certificates/tasks/check_expiry.yml new file mode 100644 index 0000000000..66ed8e4b0c --- /dev/null +++ b/ansible/roles/octavia-certificates/tasks/check_expiry.yml @@ -0,0 +1,24 @@ +--- +- name: Gather information on certificates + community.crypto.x509_certificate_info: + path: "{{ node_custom_config }}/octavia/{{ item }}" + valid_at: + point_1: "+{{ octavia_certs_expiry_limit | int }}d" + register: cert_info + delegate_to: localhost + with_items: + - "server_ca.cert.pem" + - "client_ca.cert.pem" + - "client.cert-and-key.pem" + +- name: Check whether certificates are valid within {{ octavia_certs_expiry_limit }} days + assert: + that: + - item.valid_at.point_1 + fail_msg: "{{ item.item }} will expire within {{ octavia_certs_expiry_limit }} days, on {{ item.not_after }}" + success_msg: "{{ item.item }} will not expire within {{ octavia_certs_expiry_limit }} days. It expires on {{ item.not_after }}" + quiet: True + loop: "{{ cert_info.results }}" + loop_control: + label: "{{ item.item }}" + delegate_to: localhost diff --git a/ansible/roles/octavia-certificates/tasks/main.yml b/ansible/roles/octavia-certificates/tasks/main.yml index ed58ec436c..9ba737b2bd 100644 --- a/ansible/roles/octavia-certificates/tasks/main.yml +++ b/ansible/roles/octavia-certificates/tasks/main.yml @@ -7,38 +7,45 @@ # Kolla Ansible prepares and controls the Client CA certificate and key. # Client CA is used to generate certificates for Octavia controllers. -- name: Ensure server_ca and client_ca directories exist - file: - path: "{{ octavia_certs_work_dir }}/{{ item }}" - state: "directory" - mode: 0770 - loop: - - server_ca - - client_ca +- name: Check if any certificates are going to expire + include_tasks: check_expiry.yml + when: octavia_certs_check_expiry | bool -- name: Copy openssl.cnf - copy: - src: "{{ octavia_certs_openssl_cnf_path }}" - dest: "{{ octavia_certs_work_dir }}/openssl.cnf" +- block: + - name: Ensure server_ca and client_ca directories exist + file: + path: "{{ octavia_certs_work_dir }}/{{ item }}" + state: "directory" + mode: 0770 + loop: + - server_ca + - client_ca -- import_tasks: server_ca.yml + - name: Copy openssl.cnf + copy: + src: "{{ octavia_certs_openssl_cnf_path }}" + dest: "{{ octavia_certs_work_dir }}/openssl.cnf" -- import_tasks: client_ca.yml + - import_tasks: server_ca.yml -- import_tasks: client_cert.yml + - import_tasks: client_ca.yml -- name: Ensure {{ node_custom_config }}/octavia directory exists - file: - path: "{{ node_custom_config }}/octavia" - state: "directory" - mode: 0770 + - import_tasks: client_cert.yml -- name: Copy the to-be-deployed keys and certs to {{ node_custom_config }}/octavia - copy: - src: "{{ octavia_certs_work_dir }}/{{ item.src }}" - dest: "{{ node_custom_config }}/octavia/{{ item.dest }}" - with_items: - - { src: "server_ca/server_ca.cert.pem", dest: "server_ca.cert.pem" } - - { src: "server_ca/server_ca.key.pem", dest: "server_ca.key.pem" } - - { src: "client_ca/client_ca.cert.pem", dest: "client_ca.cert.pem" } - - { src: "client_ca/client.cert-and-key.pem", dest: "client.cert-and-key.pem" } + - name: Ensure {{ node_custom_config }}/octavia directory exists + file: + path: "{{ node_custom_config }}/octavia" + state: "directory" + mode: 0770 + + - name: Copy the to-be-deployed keys and certs to {{ node_custom_config }}/octavia + copy: + src: "{{ octavia_certs_work_dir }}/{{ item.src }}" + dest: "{{ node_custom_config }}/octavia/{{ item.dest }}" + with_items: + - { src: "server_ca/server_ca.cert.pem", dest: "server_ca.cert.pem" } + - { src: "server_ca/server_ca.key.pem", dest: "server_ca.key.pem" } + - { src: "client_ca/client_ca.cert.pem", dest: "client_ca.cert.pem" } + - { src: "client_ca/client.cert-and-key.pem", dest: "client.cert-and-key.pem" } + + when: not octavia_certs_check_expiry | bool diff --git a/doc/source/reference/networking/octavia.rst b/doc/source/reference/networking/octavia.rst index 735f5a180c..72d2a04432 100644 --- a/doc/source/reference/networking/octavia.rst +++ b/doc/source/reference/networking/octavia.rst @@ -75,6 +75,16 @@ used to encrypt the CA key: .. _octavia-network: +Monitoring certificate expiry +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can use the following command to check if any of the certificates will +expire within a given number of days: + +.. code-block:: console + + kolla-ansible octavia-certificates --check-expiry + Networking ---------- diff --git a/releasenotes/notes/octavia-check-certificate-expiry-9a80a68cf31cbba4.yaml b/releasenotes/notes/octavia-check-certificate-expiry-9a80a68cf31cbba4.yaml new file mode 100644 index 0000000000..46f832abde --- /dev/null +++ b/releasenotes/notes/octavia-check-certificate-expiry-9a80a68cf31cbba4.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + The flag ``--check-expiry`` has been added to the ``octavia-certificates`` + command. ``kolla-ansible octavia-certificates --check-expiry `` will + check if the Octavia certificates are set to expire within a given number + of days. diff --git a/tests/run.yml b/tests/run.yml index b89b8a261f..47c4e8ae23 100644 --- a/tests/run.yml +++ b/tests/run.yml @@ -491,6 +491,8 @@ executable: /bin/bash chdir: "{{ kolla_ansible_src_dir }}" when: scenario == "octavia" + environment: + KOLLA_ANSIBLE_VENV_PATH: "{{ kolla_ansible_venv_path }}" - name: Run test-masakari.sh script script: diff --git a/tests/test-octavia.sh b/tests/test-octavia.sh index 4ba3457a2d..7f61093ce9 100644 --- a/tests/test-octavia.sh +++ b/tests/test-octavia.sh @@ -8,6 +8,12 @@ set -o errexit # Enable unbuffered output for Ansible in Jenkins. export PYTHONUNBUFFERED=1 +function check_certificate_expiry { + RAW_INVENTORY=/etc/kolla/inventory + source $KOLLA_ANSIBLE_VENV_PATH/bin/activate + kolla-ansible octavia-certificates --check-expiry 7 + deactivate +} function register_amphora_image { amphora_url=https://tarballs.opendev.org/openstack/octavia/test-images/test-only-amphora-x64-haproxy-ubuntu-focal.qcow2 @@ -79,6 +85,9 @@ function test_octavia { } function test_octavia_logged { + # Check if any certs expire within a week. + check_certificate_expiry + . /etc/kolla/admin-openrc.sh . ~/openstackclient-venv/bin/activate test_octavia diff --git a/tools/kolla-ansible b/tools/kolla-ansible index 9fce6e824f..278a2dbf25 100755 --- a/tools/kolla-ansible +++ b/tools/kolla-ansible @@ -197,6 +197,7 @@ Commands: stop Stop Kolla containers certificates Generate self-signed certificate for TLS *For Development Only* octavia-certificates Generate certificates for octavia deployment + --check-expiry to check if certificates expire within that many days upgrade Upgrades existing OpenStack Environment upgrade-bifrost Upgrades an existing bifrost container genconfig Generate configuration files for enabled OpenStack services @@ -263,7 +264,7 @@ function version { check_environment_coherence SHORT_OPTS="hi:p:t:k:e:CD:v" -LONG_OPTS="help,version,inventory:,playbook:,skip-tags:,tags:,key:,extra:,check,diff,verbose,configdir:,passwords:,limit:,forks:,vault-id:,ask-vault-pass,vault-password-file:,yes-i-really-really-mean-it,include-images,include-dev:,full,incremental" +LONG_OPTS="help,version,inventory:,playbook:,skip-tags:,tags:,key:,extra:,check,diff,verbose,configdir:,passwords:,limit:,forks:,vault-id:,ask-vault-pass,vault-password-file:,yes-i-really-really-mean-it,include-images,include-dev:,full,incremental,check-expiry:" RAW_ARGS="$*" ARGS=$(getopt -o "${SHORT_OPTS}" -l "${LONG_OPTS}" --name "$0" -- "$@") || { usage >&2; exit 2; } @@ -281,6 +282,7 @@ DANGER_CONFIRM= INCLUDE_IMAGES= INCLUDE_DEV= BACKUP_TYPE="full" +OCTAVIA_CERTS_EXPIRY= # Serial is not recommended and disabled by default. Users can enable it by # configuring ANSIBLE_SERIAL variable. ANSIBLE_SERIAL=${ANSIBLE_SERIAL:-0} @@ -398,6 +400,11 @@ while [ "$#" -gt 0 ]; do shift 1 ;; + (--check-expiry) + OCTAVIA_CERTS_EXPIRY="$2" + shift 2 + ;; + (--version) version exit 0 @@ -532,6 +539,9 @@ EOF (octavia-certificates) ACTION="Generate octavia Certificates" PLAYBOOK="${BASEDIR}/ansible/octavia-certificates.yml" + if [[ ! -z "${OCTAVIA_CERTS_EXPIRY}" ]]; then + EXTRA_OPTS="$EXTRA_OPTS -e octavia_certs_check_expiry=yes -e octavia_certs_expiry_limit=${OCTAVIA_CERTS_EXPIRY}" + fi ;; (genconfig) ACTION="Generate configuration files for enabled OpenStack services"