diff --git a/README.md b/README.md
index 153f61daf0cba26b90f348dae81d173f70f6317f..5bd5afd4bc2ecf9244b23068c6caa9411ba00dfd 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 8bd06e302ea042064d22b7d11a01ae8875258076..d13a80e3435115cd2670dc2c7e09303771610893 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 0000000000000000000000000000000000000000..707e816eaf728a39f8cb64e6a9b971b296f91755
--- /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 0000000000000000000000000000000000000000..82b927a41951ae45a8be0903a30ecf8069cec22b
--- /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 0000000000000000000000000000000000000000..8d453059e82282882c865aa6ae45a0e152334b2c
--- /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 0000000000000000000000000000000000000000..906b44d34b000ba58e0412c9fce15ba35ee48de9
--- /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 0000000000000000000000000000000000000000..ff3b9643bb90ad2989e0a84454f964b372e210ca
--- /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 0000000000000000000000000000000000000000..b2660140e755d98e1a73c5e7e14154ee5164913e
--- /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 0000000000000000000000000000000000000000..83d0176139ed32ed3a852424625407aed125f043
--- /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