From f79bc691159d3890683b862bc1b7da8fc2f3a363 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Franti=C5=A1ek=20Dvo=C5=99=C3=A1k?= <valtri@civ.zcu.cz>
Date: Wed, 30 Dec 2020 18:01:33 +0100
Subject: [PATCH] Ansible role for generating of the certificates

---
 README.md                                |  8 ++++-
 common/ctx.yaml                          |  2 ++
 roles/certgen/defaults/main.yml          |  8 +++++
 roles/certgen/tasks/ca.yml               | 37 +++++++++++++++++++++++
 roles/certgen/tasks/cert.yml             |  9 ++++++
 roles/certgen/tasks/cert_csr.yml         | 19 ++++++++++++
 roles/certgen/tasks/cert_remote_sign.yml | 33 ++++++++++++++++++++
 roles/certgen/tasks/cert_result.yml      | 38 ++++++++++++++++++++++++
 roles/certgen/tasks/main.yml             |  7 +++++
 9 files changed, 160 insertions(+), 1 deletion(-)
 create mode 100644 roles/certgen/defaults/main.yml
 create mode 100644 roles/certgen/tasks/ca.yml
 create mode 100644 roles/certgen/tasks/cert.yml
 create mode 100644 roles/certgen/tasks/cert_csr.yml
 create mode 100644 roles/certgen/tasks/cert_remote_sign.yml
 create mode 100644 roles/certgen/tasks/cert_result.yml
 create mode 100644 roles/certgen/tasks/main.yml

diff --git a/README.md b/README.md
index 153f61d..5bd5afd 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,13 @@ Primary goal of this project is to build Hadoop cluster. But the most part is ge
 Locally installed:
 
 * [Terraform](https://www.terraform.io/)
-* [Ansible](https://www.ansible.com/)
+* [Ansible](https://www.ansible.com/) >= 2.9.10
+ * with community.crypto collection
+* access to OpenStack - the *cloud.yaml* file
+
+Steps to install Ansible dependencies:
+
+  ansible-galaxy collection install community.crypto
 
 # Hadoop image
 
diff --git a/common/ctx.yaml b/common/ctx.yaml
index 8bd06e3..d13a80e 100644
--- a/common/ctx.yaml
+++ b/common/ctx.yaml
@@ -6,6 +6,8 @@ timezone: Europe/Prague
 
 packages:
   - fail2ban
+  - python-cryptography
+  - python-openssl
   - rsync
   - wget
   - mc
diff --git a/roles/certgen/defaults/main.yml b/roles/certgen/defaults/main.yml
new file mode 100644
index 0000000..707e816
--- /dev/null
+++ b/roles/certgen/defaults/main.yml
@@ -0,0 +1,8 @@
+certgen_ca_dir: /root/CA
+certgen_target_dir: /etc/security/certificates
+
+certgen_ca_subject: "/CN={{ certgen_master }}-certgen-CA/"
+certgen_cert_expire: "+3650d"
+certgen_digest: sha256
+certgen_key_size: 2048
+certgen_key_type: RSA
diff --git a/roles/certgen/tasks/ca.yml b/roles/certgen/tasks/ca.yml
new file mode 100644
index 0000000..82b927a
--- /dev/null
+++ b/roles/certgen/tasks/ca.yml
@@ -0,0 +1,37 @@
+---
+- name: CA directory with certs subdirectory
+  file:
+    path: "{{ certgen_ca_dir }}/certs"
+    mode: 0755
+    state: directory
+
+- name: Generate CA Private Key
+  community.crypto.openssl_privatekey:
+    path: "{{ certgen_ca_dir }}/cakey.pem"
+    size: "{{ certgen_key_size }}"
+    type: "{{ certgen_key_type }}"
+
+- name: Create CA Certificate Signing Request
+  community.crypto.openssl_csr:
+    path: "{{ certgen_ca_dir }}/careq.csr"
+    common_name: "{{ certgen_ca_subject }}"
+    digest: "{{ certgen_digest }}"
+    # key_usage:
+    #   - keyCertSign
+    #   - cRLSign
+    privatekey_path: "{{ certgen_ca_dir }}/cakey.pem"
+    use_common_name_for_san: no
+
+- name: Create Public CA Certificate
+  community.crypto.x509_certificate:
+    path: "{{ certgen_ca_dir }}/cacert.pem"
+    csr_path: "{{ certgen_ca_dir }}/careq.csr"
+    privatekey_path: "{{ certgen_ca_dir }}/cakey.pem"
+    provider: selfsigned
+
+- name: Create PKCS12 CA Certificate
+  community.crypto.openssl_pkcs12:
+    path: "{{ certgen_ca_dir }}/cacerts"
+    friendly_name: "{{ ansible_fqdn }}-CA"
+    certificate_path: "{{ certgen_ca_dir }}/cacert.pem"
+    privatekey_path: "{{ certgen_ca_dir }}/cakey.pem"
diff --git a/roles/certgen/tasks/cert.yml b/roles/certgen/tasks/cert.yml
new file mode 100644
index 0000000..8d45305
--- /dev/null
+++ b/roles/certgen/tasks/cert.yml
@@ -0,0 +1,9 @@
+---
+- name: Include Certificate Signature Request
+  include: cert_csr.yml
+
+- name: Include remote sign
+  include: cert_remote_sign.yml
+
+- name: Include copying result certificate
+  include: cert_result.yml
diff --git a/roles/certgen/tasks/cert_csr.yml b/roles/certgen/tasks/cert_csr.yml
new file mode 100644
index 0000000..906b44d
--- /dev/null
+++ b/roles/certgen/tasks/cert_csr.yml
@@ -0,0 +1,19 @@
+---
+- name: Certificates target directory
+  file:
+    path: "{{ certgen_target_dir }}"
+    mode: 0755
+    state: directory
+
+- name: Generate Private Key
+  community.crypto.openssl_privatekey:
+    path: "{{ certgen_target_dir }}/hostkey.pem"
+    size: "{{ certgen_key_size }}"
+    type: "{{ certgen_key_type }}"
+
+- name: Create Certificate Signing Request
+  community.crypto.openssl_csr:
+    path: "{{ certgen_target_dir }}/hostreq.csr"
+    common_name: "{{ ansible_fqdn }}"
+    digest: "{{ certgen_digest }}"
+    privatekey_path: "{{ certgen_target_dir }}/hostkey.pem"
diff --git a/roles/certgen/tasks/cert_remote_sign.yml b/roles/certgen/tasks/cert_remote_sign.yml
new file mode 100644
index 0000000..ff3b964
--- /dev/null
+++ b/roles/certgen/tasks/cert_remote_sign.yml
@@ -0,0 +1,33 @@
+---
+- name: Wait for CA setup is finalized
+  wait_for:
+    path: "{{ certgen_ca_dir }}/cacert.pem"
+  delegate_to: "{{ certgen_master }}"
+  become: true
+
+- name: Fetch CSR
+  fetch:
+    src: "{{ certgen_target_dir }}/hostreq.csr"
+    dest: "/tmp/._ansible_certgen/{{ ansible_fqdn }}.csr"
+    flat: yes
+    fail_on_missing: yes
+
+- name: Copy CSR to CA
+  copy:
+    src: "/tmp/._ansible_certgen/{{ ansible_fqdn }}.csr"
+    dest: "{{ certgen_ca_dir }}/certs/{{ ansible_fqdn }}.csr"
+    mode: 0600
+  delegate_to: "{{ certgen_master }}"
+  become: true
+
+- name: Sign Certificate
+  community.crypto.x509_certificate:
+    path: "{{ certgen_ca_dir }}/certs/{{ ansible_fqdn }}.crt"
+    csr_path: "{{ certgen_ca_dir }}/certs/{{ ansible_fqdn }}.csr"
+    ownca_digest: "{{ certgen_digest }}"
+    ownca_not_after: "{{ certgen_cert_expire }}"
+    ownca_path: "{{ certgen_ca_dir }}/cacert.pem"
+    ownca_privatekey_path: "{{ certgen_ca_dir }}/cakey.pem"
+    provider: ownca
+  delegate_to: "{{ certgen_master }}"
+  become: true
diff --git a/roles/certgen/tasks/cert_result.yml b/roles/certgen/tasks/cert_result.yml
new file mode 100644
index 0000000..b266014
--- /dev/null
+++ b/roles/certgen/tasks/cert_result.yml
@@ -0,0 +1,38 @@
+---
+- name: Fetch certificate
+  fetch:
+    src: "{{ certgen_ca_dir }}/certs/{{ ansible_fqdn }}.crt"
+    dest: "/tmp/._ansible_certgen/{{ ansible_fqdn }}.crt"
+    flat: yes
+    fail_on_missing: yes
+  delegate_to: "{{ certgen_master }}"
+  become: true
+
+- name: Fetch CA certificate
+  fetch:
+    src: "{{ certgen_ca_dir }}/cacert.pem"
+    dest: "/tmp/._ansible_certgen/CA/ca.crt"
+    flat: yes
+    fail_on_missing: yes
+  delegate_to: "{{ certgen_master }}"
+  become: true
+
+- name: Copy certificate to target machine
+  copy:
+    src: "/tmp/._ansible_certgen/{{ ansible_fqdn }}.crt"
+    dest: "{{ certgen_target_dir }}/hostcert.pem"
+    mode: 0644
+
+- name: Copy CA certificate to target machine
+  copy:
+    src: "/tmp/._ansible_certgen/CA/ca.crt"
+    dest: "{{ certgen_target_dir }}/cacert.pem"
+    mode: 0644
+
+- name: Create PKCS12 certificate at target machine
+  community.crypto.openssl_pkcs12:
+    path: "{{ certgen_target_dir }}/server.keystore"
+    friendly_name: "{{ ansible_fqdn }}"
+    certificate_path: "{{ certgen_target_dir }}/hostcert.pem"
+    other_certificates: "{{ certgen_target_dir }}/cacert.pem"
+    privatekey_path: "{{ certgen_target_dir }}/hostkey.pem"
diff --git a/roles/certgen/tasks/main.yml b/roles/certgen/tasks/main.yml
new file mode 100644
index 0000000..83d0176
--- /dev/null
+++ b/roles/certgen/tasks/main.yml
@@ -0,0 +1,7 @@
+---
+- name: Include CA setup
+  include: ca.yml
+  when: certgen_master == ansible_nodename
+
+- name: Include machine certificate
+  include: cert.yml
-- 
GitLab