--- # 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: next_serial_no: "{{ serial_no['content'] | b64decode | int + 1 }}" ansible_python_interpreter: "{{ pki_setup_host_python_interpreter }}" delegate_to: "{{ pki_setup_host }}" block: - name: Create directories for certificate authority {{ ca.name }} file: state: directory path: "{{ item.path }}" owner: "{{ item.owner | default(pki_owner) | default(omit) }}" group: "{{ item.group | default(pki_group) | default(omit) }}" mode: "{{ item.mode | default('0755') }}" with_items: - path: "{{ ca_dir }}" - path: "{{ ca_dir ~ '/csr' }}" mode: "{{ pki_key_dir_mode }}" - path: "{{ ca_dir ~ '/private' }}" mode: "{{ pki_key_dir_mode }}" - path: "{{ ca_dir ~ '/certs' }}" mode: "{{ pki_cert_dir_mode }}" # NOTE(noonedeadpunk): Incorrect permissions lead to CA certs re-generation as # openssl_privatekey gets changed when harmonizing ownership/permissions - name: Ensure private key has proper ownership file: state: file path: "{{ ca_dir ~ '/private/' ~ ca.name ~ '.key.pem' }}" mode: "{{ ca.key_mode | default(pki_key_mode) }}" owner: "{{ ca.key_owner | default(pki_owner) | default(omit) }}" group: "{{ ca.key_group | default(pki_group) | default(omit) }}" failed_when: false - name: Initialise the serial number for {{ ca.name }} copy: content: "999" dest: "{{ ca_dir ~ '/serial' }}" force: false - name: Generate CA private key for {{ ca.name }} community.crypto.openssl_privatekey: path: "{{ ca_dir ~ '/private/' ~ ca.name ~ '.key.pem' }}" passphrase: "{{ ca.key_passphrase | default(omit) }}" cipher: "{{ ('key_passphrase' in ca and ca.key_passphrase) | ternary('auto', omit) }}" backup: "{{ ca.backup | default(True) }}" mode: "{{ ca.key_mode | default(pki_key_mode) }}" owner: "{{ ca.key_owner | default(pki_owner) | default(omit) }}" group: "{{ ca.key_group | default(pki_group) | default(omit) }}" register: ca_privkey - name: Read the serial number for {{ ca.name }} slurp: src: "{{ pki_dir ~ '/roots/' ~ ca.name ~ '/serial' }}" register: serial_no - name: Create the CA CSR for {{ ca.name }} community.crypto.openssl_csr: path: "{{ ca_dir }}/csr/ca_csr-{{ next_serial_no }}.csr" privatekey_path: "{{ ca_privkey.filename }}" privatekey_passphrase: "{{ ca.key_passphrase | default(omit) }}" common_name: "{{ ca.cn }}" basic_constraints_critical: true basic_constraints: "{{ ca.basic_constraints }}" key_usage: "{{ ca.key_usage }}" country_name: "{{ ca.country_name | default(omit) }}" state_or_province_name: "{{ ca.state_or_province_name | default(omit) }}" locality_name: "{{ ca.locality_name | default(omit) }}" organization_name: "{{ ca.organizataion_name | default(omit) }}" organizational_unit_name: "{{ ca.organization_unit_name | default(omit) }}" subject: "{{ cert.subject | default(omit) }}" backup: "{{ ca.backup | default(True) }}" register: ca_csr when: - ca_privkey is changed or pki_regen_ca == ca.name or (pki_regen_ca | lower) == 'true' - name: Write out the new serial number for {{ ca.name }} copy: content: "{{ next_serial_no }}" dest: "{{ ca_dir }}/serial" when: ca_csr is changed - name: Sign the selfsigned Root CA CSR for {{ ca.name }} community.crypto.x509_certificate: path: "{{ ca_cert_prefix ~ '-' ~ next_serial_no ~ '.crt' }}" csr_path: "{{ ca_csr.filename }}" provider: "selfsigned" privatekey_path: "{{ ca_privkey.filename }}" privatekey_passphrase: "{{ ca.key_passphrase | default(omit) }}" selfsigned_not_after: "{{ ca.not_after }}" backup: "{{ ca.backup | default(True) }}" register: ca_selfsigned_crt when: - ca.provider == 'selfsigned' - ca_csr is changed notify: - "{{ pki_handler_ca_changed }}" - name: Sign the intermediate CA CSR for {{ ca.name }} vars: community.crypto.x509_certificate: path: "{{ ca_cert_prefix ~ '-' ~ next_serial_no ~ '.crt' }}" csr_path: "{{ ca_csr.filename }}" provider: "ownca" ownca_privatekey_path: "{{ pki_dir ~ '/roots/' ~ ca.signed_by ~ '/private/' ~ ca.signed_by ~ '.key.pem' }}" ownca_privatekey_passphrase: "{{ ca.ownca_key_passphrase | default(omit) }}" ownca_path: "{{ pki_dir ~ '/roots/' ~ ca.signed_by ~ '/certs/' ~ ca.signed_by ~ '.crt' }}" ownca_not_after: "{{ ca.not_after }}" backup: "{{ ca.backup | default(True) }}" register: ca_ownca_crt when: - ca.provider == 'ownca' - ca_csr is changed notify: - "{{ pki_handler_ca_changed }}" - name: Symlink the certificate name to the most recently generated file: src: "{{ (ca_selfsigned_crt.filename | default(ca_ownca_crt.filename)) | basename }}" dest: "{{ ca_cert_prefix ~ '.crt' }}" state: link when: ca_ownca_crt is changed or ca_selfsigned_crt is changed - name: Get certificate info for {{ ca.name }} community.crypto.x509_certificate_info: path: "{{ ca_selfsigned_crt.filename | default(ca_ownca_crt.filename) }}" register: ca_cert_info when: ca_ownca_crt is changed or ca_selfsigned_crt is changed - name: Save certificate info for {{ ca.name }} copy: content: "{{ ca_cert_info | to_nice_yaml }}" dest: "{{ (ca_selfsigned_crt.filename | default(ca_ownca_crt.filename)) ~ '.info' }}" when: ca_ownca_crt is changed or ca_selfsigned_crt is changed - name: Check if intermediate certificate chain exists stat: path: "{{ ca_cert_prefix ~ '-chain.crt' }}" register: chain_result when: - ca.provider == 'ownca' - name: Create intermediate certificate chain vars: ownca_path: "{{ pki_dir ~ '/roots/' ~ ca.signed_by ~ '/certs/' ~ ca.signed_by ~ '.crt' }}" cert_path: "{{ ca_cert_prefix ~ '.crt' }}" cert_chain_path: "{{ ca_cert_prefix ~ '-chain.crt' }}" shell: cmd: "cat {{ cert_path }} {{ ownca_path }} > {{ cert_chain_path }}" when: - ca_ownca_crt is changed or not (chain_result.stat.exists | default(true)) - ca.provider == 'ownca'