ansible-role-pki/tasks/standalone/create_ca.yml

168 lines
7.0 KiB
YAML

---
# 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: no
- 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: yes
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'