diff --git a/pki/defaults/main.yml b/pki/defaults/main.yml new file mode 100644 index 00000000..30a0364b --- /dev/null +++ b/pki/defaults/main.yml @@ -0,0 +1,15 @@ +--- +pki_dir: /etc/pki # Where to store PKI files + +pki_ca_cn: Null # Certificate Authority Commmon Name +pki_ca_host: Null # Host where the CA is located +pki_ca_filename: Null # Filename used to created CA related file +pki_ca_password: Null # Password for the key of the CA + + +# Private variable, please don't customize them +pki_ca_key: "{{ pki_dir }}/private/{{ pki_ca_filename | mandatory }}.key" +# pki_ca_csr: "{{ pki_dir }}/certs/{{ pki_ca_filename | mandatory }}.crt" +pki_ca_crt: "{{ pki_dir }}/certs/{{ pki_ca_filename | mandatory }}.crt" +pki_certificate_crt: "{{ pki_dir }}/certs/{{ ansible_fqdn }}.crt" +pki_certificate_key: "{{ pki_dir }}/private/{{ ansible_fqdn }}.key" diff --git a/pki/tasks/ca.yml b/pki/tasks/ca.yml new file mode 100644 index 00000000..caae52d6 --- /dev/null +++ b/pki/tasks/ca.yml @@ -0,0 +1,28 @@ +--- +- name: Create private key with password protection + community.crypto.openssl_privatekey: + path: "{{ pki_ca_key }}" + passphrase: "{{ pki_ca_password | mandatory }}" + cipher: auto + +- name: Create certificate signing request (CSR) for CA certificate + community.crypto.openssl_csr_pipe: + privatekey_path: "{{ pki_ca_key }}" + privatekey_passphrase: "{{ pki_ca_password | mandatory }}" + common_name: "{{ pki_ca_cn | mandatory }}" + use_common_name_for_san: false + basic_constraints: + - 'CA:TRUE' + basic_constraints_critical: yes + key_usage: + - keyCertSign + key_usage_critical: true + register: ca_csr + +- name: Create self-signed CA certificate from CSR + community.crypto.x509_certificate: + path: "{{ pki_ca_crt }}" + csr_content: "{{ ca_csr.csr }}" + privatekey_path: "{{ pki_ca_key }}" + privatekey_passphrase: "{{ pki_ca_password | mandatory }}" + provider: selfsigned diff --git a/pki/tasks/main.yml b/pki/tasks/main.yml new file mode 100644 index 00000000..f4d78ceb --- /dev/null +++ b/pki/tasks/main.yml @@ -0,0 +1,33 @@ +--- + +# Prerequisites +# TODO Python packages may need to be differente based on debian version +- name: Install python 2 cryptography + apt: + name: python-cryptography + state: present + when: ansible_python['executable'] == "/usr/bin/python" + +- name: Install python 3 cryptography + apt: + name: python3-cryptography + state: present + when: ansible_python['executable'] == "/usr/bin/python3" + +- name: Creates PKI tree directories + file: + path: "{{ item }}" + mode: 0700 + state: directory + loop: + - "{{ pki_dir }}/certs" + - "{{ pki_dir }}/private" + + +# Create Certificat Authority (CA) +- include: ca.yml + when: inventory_hostname == pki_ca_host and not ansible_check_mode + + +# Create a certificate signed by the CA +- include: signed_certificate.yml diff --git a/pki/tasks/signed_certificate.yml b/pki/tasks/signed_certificate.yml new file mode 100644 index 00000000..15dbb42b --- /dev/null +++ b/pki/tasks/signed_certificate.yml @@ -0,0 +1,90 @@ +--- +# CA certificate +- name: Check whether CA certificate exists + stat: + path: "{{ pki_ca_crt }}" + delegate_to: "{{ pki_ca_host | mandatory }}" + run_once: true + register: ca_certificate_exists + +- name: Fail if CA doesn't exists + fail: + msg: "CA '{{ pki_ca_crt }}' on host '{{ pki_ca_host }}' doesn't exists! You need to create one before continuing." + when: not ca_certificate_exists.stat.exists + +- name: Read existing CA certificate if exists + slurp: + src: "{{ pki_ca_crt }}" + when: ca_certificate_exists.stat.exists + delegate_to: "{{ pki_ca_host | mandatory }}" + run_once: true + register: ca_certificate + +- name: Write CA certificate file + copy: + dest: "{{ pki_ca_crt }}" + content: "{{ ca_certificate.content | b64decode }}" + run_once: true + register: ca_certificate + + +# Create new signed certificate +- name: Create private key for new certificate + community.crypto.openssl_privatekey: + path: "{{ pki_certificate_key }}" + run_once: true + +- name: Create certificate signing request (CSR) for new certificate + community.crypto.openssl_csr_pipe: + privatekey_path: "{{ pki_certificate_key }}" + common_name: "{{ ansible_fqdn }}" + run_once: true + register: csr + +- name: Check whether certificate exists + stat: + path: "{{ pki_certificate_crt }}" + run_once: true + register: certificate_exists + +- name: Read existing certificate if exists + slurp: + src: "{{ pki_certificate_crt }}" + when: certificate_exists.stat.exists + run_once: true + register: certificate + +- name: Sign certificate with CA + community.crypto.x509_certificate_pipe: + content: "{{ (certificate.content | b64decode) if certificate_exists.stat.exists else omit }}" + csr_content: "{{ csr.csr }}" + provider: ownca + ownca_path: "{{ pki_ca_crt }}" + ownca_privatekey_path: "{{ pki_ca_key }}" + ownca_privatekey_passphrase: "{{ pki_ca_password | mandatory}}" + delegate_to: "{{ pki_ca_host | mandatory }}" + run_once: true + register: certificate + when: not ansible_check_mode + +- name: Write certificate file + copy: + dest: "{{ pki_certificate_crt }}" + content: "{{ certificate.certificate }}" + run_once: true + when: certificate is changed and not ansible_check_mode + +- name: Write certificate file on the CA host + copy: + dest: "{{ pki_certificate_crt }}" + content: "{{ certificate.certificate }}" + delegate_to: "{{ pki_ca_host | mandatory }}" + run_once: true + when: certificate is changed and not ansible_check_mode + + +# Allow other roles to know if some certifiates has changed +- name: Set fact, pki_changed + when: certificate is changed or ca_certificate is changed + set_fact: + pki_changed: True