Execution
Date 08 Dec 2025 13:39:52 +0000
Duration 00:35:02.03
Controller aio1.openstack.local
User root
Versions
Ansible 2.18.6
ara 1.7.4 / 1.7.4
Python 3.12.3
Summary
2 Hosts
1377 Tasks
1365 Results
104 Plays
504 Files
0 Records

File: /home/zuul/src/opendev.org/openstack/ansible-role-pki/tasks/standalone/sign_cert.yml

---
# Copyright 2021, BBC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

- name: Create certificate {{ cert.name }}
  vars:
    ansible_python_interpreter: "{{ pki_setup_host_python_interpreter }}"
    _cert_file: "{{ cert_dir ~ '/certs/' ~ cert.name ~ '.crt' }}"
    _cert_full_chain_file: "{{ cert_dir ~ '/certs/' ~ cert.name ~ '-chain.crt' }}"
    _cert_ca_bundle_file: "{{ cert_dir ~ '/certs/' ~ cert.name ~ '-ca_bundle.crt' }}"
    _ca_file: "{{ pki_dir ~ '/roots/' ~ cert.signed_by ~ '/certs/' ~ cert.signed_by ~ '.crt' }}"
    _ca_bundle_file: "{{ pki_dir ~ '/roots/' ~ cert.signed_by ~ '/certs/' ~ cert.signed_by ~ '-chain.crt' }}"
  delegate_to: "{{ pki_setup_host }}"
  block:
    - name: Generate certificate private key for {{ cert.name }}
      community.crypto.openssl_privatekey:
        path: "{{ cert_dir ~ '/private/' ~ cert.name ~ '.key.pem' }}"
        passphrase: "{{ cert.key_passphrase | default(omit) }}"
        cipher: "{{ ('key_passphrase' in cert and cert.key_passphrase) | ternary('auto', omit) }}"
        force: "{{ pki_regen_cert == cert.name or ((pki_regen_cert | lower) == 'true') }}"
        format: "{{ cert.key_format | default(omit) }}"
      register: cert_privkey

    - name: Create the CSR for {{ cert.name }}
      vars:
        generated_san: >-
          {{
            ['DNS:' + (cert.san.dns | unique | join(',DNS:')) if cert.san.dns | default([]) else '',
             'IP:' + (cert.san.ip | unique | join(',IP:')) if cert.san.ip | default([]) else '']
            | select() | join(',')
          }}
      community.crypto.openssl_csr:
        path: "{{ cert_dir ~ '/csr/' ~ cert.name ~ '.csr' }}"
        privatekey_path: "{{ cert_privkey.filename }}"
        privatekey_passphrase: "{{ cert.key_passphrase | default(omit) }}"
        common_name: "{{ cert.cn | default(omit) }}"
        basic_constraints_critical: true
        basic_constraints: "{{ cert.basic_constraints | default(omit) }}"
        key_usage: "{{ cert.key_usage | default(omit) }}"
        extended_key_usage: "{{ cert.extended_key_usage | default(omit) }}"
        # NOTE(damiandabrowski) After 2026.1 switch to just:
        #                       subject_alt_name: "{{ generated_san | default(omit) }}"
        subject_alt_name: "{{ (cert.san is defined and cert.san is not string) | ternary(generated_san, cert.san | default(omit)) }}"
        country_name: "{{ cert.country_name | default(omit) }}"
        state_or_province_name: "{{ cert.state_or_province_name | default(omit) }}"
        locality_name: "{{ cert.locality_name | default(omit) }}"
        organization_name: "{{ cert.organization_name | default(omit) }}"
        organizational_unit_name: "{{ cert.organization_unit_name | default(omit) }}"
        subject: "{{ cert.subject | default(omit) }}"
        force: "{{ pki_regen_cert == cert.name or ((pki_regen_cert | lower) == 'true') }}"
      register: cert_csr

    - name: Sign the certificate CSR for {{ cert.name }}
      community.crypto.x509_certificate:
        path: "{{ _cert_file }}"
        csr_path: "{{ cert_csr.filename }}"
        ownca_path: "{{ _ca_file }}"
        ownca_privatekey_path: "{{ pki_dir ~ '/roots/' ~ cert.signed_by ~ '/private/' ~ cert.signed_by ~ '.key.pem' }}"
        ownca_privatekey_passphrase: "{{ cert.ownca_key_passphrase | default(omit) }}"
        ownca_not_after: "{{ ('ttl' in cert) | ternary('+' ~ cert.get('ttl'), omit) }}"
        provider: ownca
        force: "{{ pki_regen_cert == cert.name or ((pki_regen_cert | lower) == 'true') }}"
      register: cert_crt
      when:
        - cert.provider == 'ownca'
        - cert_csr is changed
      notify:
        - "{{ pki_handler_cert_changed }}"
      ignore_errors: "{{ ansible_check_mode }}"

    - name: Get certificate info for {{ cert.name }}
      community.crypto.x509_certificate_info:
        path: "{{ cert_crt.filename }}"
      register: cert_info
      when: cert_crt is changed

    - name: Save certificate info for {{ cert.name }}
      ansible.builtin.copy:
        content: "{{ cert_info | to_nice_yaml }}"
        dest: "{{ cert_dir ~ '/certs/' ~ cert.name ~ '.info' }}"
      when: cert_crt is changed

    - name: Create certificate ca bundle for {{ cert.name }}
      ansible.builtin.copy:
        src: "{{ _ca_bundle_file }}"
        remote_src: true
        dest: "{{ _cert_ca_bundle_file }}"

    - name: Create certificate full chain for {{ cert.name }}
      shell:
        cmd: "cat {{ _cert_file }} {{ _ca_file }} > {{ _cert_full_chain_file }}"
        creates: "{{ (cert_crt is not changed) | ternary(_cert_full_chain_file, omit) }}"