diff --git a/roles/ipareplica/library/ipareplica_ds_apply_updates.py b/roles/ipareplica/library/ipareplica_ds_apply_updates.py
index 66aecd2680e688a639e4492a6680177fe27f58c0..3796874bc3f5dd7e85ffccd1b33940582e17450d 100644
--- a/roles/ipareplica/library/ipareplica_ds_apply_updates.py
+++ b/roles/ipareplica/library/ipareplica_ds_apply_updates.py
@@ -123,8 +123,8 @@ def main():
             ccache=dict(required=True),
             _ca_enabled=dict(required=False, type='bool'),
             _ca_file=dict(required=False),
-            _dirsrv_pkcs12_info=dict(required=False),
-            _pkinit_pkcs12_info=dict(required=False),
+            _dirsrv_pkcs12_info=dict(required=False, type='list'),
+            _pkinit_pkcs12_info=dict(required=False, type='list'),
             _top_dir=dict(required=True),
             dirman_password=dict(required=True, no_log=True),
             ds_ca_subject=dict(required=True),
diff --git a/roles/ipareplica/library/ipareplica_ds_enable_ssl.py b/roles/ipareplica/library/ipareplica_ds_enable_ssl.py
index 88c5f0b3e7a6cd53ad0bf1aebe954293be208ecd..a1b638efccecee96d68e62a7cd529db3d02dd545 100644
--- a/roles/ipareplica/library/ipareplica_ds_enable_ssl.py
+++ b/roles/ipareplica/library/ipareplica_ds_enable_ssl.py
@@ -119,8 +119,8 @@ def main():
             ccache=dict(required=True),
             _ca_enabled=dict(required=False, type='bool'),
             _ca_file=dict(required=False),
-            _dirsrv_pkcs12_info=dict(required=False),
-            _pkinit_pkcs12_info=dict(required=False),
+            _dirsrv_pkcs12_info=dict(required=False, type='list'),
+            _pkinit_pkcs12_info=dict(required=False, type='list'),
             _top_dir=dict(required=True),
             dirman_password=dict(required=True, no_log=True),
             ds_ca_subject=dict(required=True),
diff --git a/roles/ipareplica/library/ipareplica_krb_enable_ssl.py b/roles/ipareplica/library/ipareplica_krb_enable_ssl.py
index 1a73414d8add47c49aef29ea18e88886dc552f1d..a302b0faf4949746470eb34b354097d47af32334 100644
--- a/roles/ipareplica/library/ipareplica_krb_enable_ssl.py
+++ b/roles/ipareplica/library/ipareplica_krb_enable_ssl.py
@@ -106,7 +106,7 @@ def main():
             ccache=dict(required=True),
             _ca_enabled=dict(required=False, type='bool'),
             _ca_file=dict(required=False),
-            _pkinit_pkcs12_info=dict(required=False),
+            _pkinit_pkcs12_info=dict(required=False, type='list'),
             _top_dir=dict(required=True),
             dirman_password=dict(required=True, no_log=True),
         ),
diff --git a/roles/ipareplica/library/ipareplica_prepare.py b/roles/ipareplica/library/ipareplica_prepare.py
index 0478d7de9c6ae95286bb179f7089f3eca13ada59..ed89b692c59bf22d0e618f8125bf663ee6265817 100644
--- a/roles/ipareplica/library/ipareplica_prepare.py
+++ b/roles/ipareplica/library/ipareplica_prepare.py
@@ -195,6 +195,7 @@ import os
 import tempfile
 import traceback
 import six
+from shutil import copyfile
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils.ansible_ipa_replica import (
@@ -485,6 +486,21 @@ def main():
             "certificate are not signed by the same CA "
             "certificate")
 
+    # Copy pkcs12_files to make them persistent till deployment is done
+    # and encode certificates for ansible compatibility
+    if http_pkcs12_info is not None:
+        copyfile(http_pkcs12_file.name, "/etc/ipa/.tmp_pkcs12_http")
+        http_pkcs12_info = ("/etc/ipa/.tmp_pkcs12_http", http_pin)
+        http_ca_cert = ""
+    if dirsrv_pkcs12_info is not None:
+        copyfile(dirsrv_pkcs12_file.name, "/etc/ipa/.tmp_pkcs12_dirsrv")
+        dirsrv_pkcs12_info = ("/etc/ipa/.tmp_pkcs12_dirsrv", dirsrv_pin)
+        dirsrv_ca_cert = ""
+    if pkinit_pkcs12_info is not None:
+        copyfile(pkinit_pkcs12_file.name, "/etc/ipa/.tmp_pkcs12_pkinit")
+        pkinit_pkcs12_info = ("/etc/ipa/.tmp_pkcs12_pkinit", pkinit_pin)
+        pkinit_ca_cert = ""
+
     ansible_log.debug("-- FQDN --")
 
     installutils.verify_fqdn(config.host_name, options.no_host_dns)
diff --git a/roles/ipareplica/library/ipareplica_setup_ca.py b/roles/ipareplica/library/ipareplica_setup_ca.py
index 850ceb964b82e14e4a7fde5342fa3cf26c160c91..d71299b6754fce6cf7aae7f907526c4c86a1c30d 100644
--- a/roles/ipareplica/library/ipareplica_setup_ca.py
+++ b/roles/ipareplica/library/ipareplica_setup_ca.py
@@ -138,8 +138,8 @@ def main():
             _ca_file=dict(required=False),
             _kra_enabled=dict(required=False, type='bool'),
             _kra_host_name=dict(required=False),
-            _dirsrv_pkcs12_info=dict(required=False),
-            _pkinit_pkcs12_info=dict(required=False),
+            _dirsrv_pkcs12_info=dict(required=False, type='list'),
+            _pkinit_pkcs12_info=dict(required=False, type='list'),
             _top_dir=dict(required=True),
             _ca_subject=dict(required=True),
             _subject_base=dict(required=True),
diff --git a/roles/ipareplica/library/ipareplica_setup_custodia.py b/roles/ipareplica/library/ipareplica_setup_custodia.py
index e9e4047a4cc81476b267efcc83eca6c6bd3f258a..5a74e876782cb31660f0656b47c9cfd3270c4e4c 100644
--- a/roles/ipareplica/library/ipareplica_setup_custodia.py
+++ b/roles/ipareplica/library/ipareplica_setup_custodia.py
@@ -118,7 +118,7 @@ def main():
             _ca_file=dict(required=False),
             _kra_enabled=dict(required=False, type='bool'),
             _kra_host_name=dict(required=False),
-            _pkinit_pkcs12_info=dict(required=False),
+            _pkinit_pkcs12_info=dict(required=False, type='list'),
             _top_dir=dict(required=True),
             dirman_password=dict(required=True, no_log=True),
         ),
diff --git a/roles/ipareplica/library/ipareplica_setup_ds.py b/roles/ipareplica/library/ipareplica_setup_ds.py
index 39e3348a9e6e85957f8c0263f518c895e84d58ac..8a44120b4634cc5dc4f39dbc85898a7b694f9e8d 100644
--- a/roles/ipareplica/library/ipareplica_setup_ds.py
+++ b/roles/ipareplica/library/ipareplica_setup_ds.py
@@ -190,7 +190,7 @@ def main():
             ccache=dict(required=True),
             installer_ccache=dict(required=True),
             _ca_enabled=dict(required=False, type='bool'),
-            _dirsrv_pkcs12_info=dict(required=False),
+            _dirsrv_pkcs12_info=dict(required=False, type='list'),
             _top_dir=dict(required=True),
             _add_to_ipaservers=dict(required=True, type='bool'),
             _ca_subject=dict(required=True),
diff --git a/roles/ipareplica/library/ipareplica_setup_http.py b/roles/ipareplica/library/ipareplica_setup_http.py
index a33587c766fcc6b7680d9e6ae555d52d0c40b934..987ea9598c44cc9ea08fa25d68ec5e42be3b62f0 100644
--- a/roles/ipareplica/library/ipareplica_setup_http.py
+++ b/roles/ipareplica/library/ipareplica_setup_http.py
@@ -115,7 +115,7 @@ def main():
             ccache=dict(required=True),
             _ca_enabled=dict(required=False, type='bool'),
             _ca_file=dict(required=False),
-            _http_pkcs12_info=dict(required=False),
+            _http_pkcs12_info=dict(required=False, type='list'),
             _top_dir=dict(required=True),
             dirman_password=dict(required=True, no_log=True),
         ),
diff --git a/roles/ipareplica/library/ipareplica_setup_krb.py b/roles/ipareplica/library/ipareplica_setup_krb.py
index 7763f76ff0708b1e57d43f409869f62f104e8b4f..c8d09f732da2578f499bfeb6dff8d8a58175ee3d 100644
--- a/roles/ipareplica/library/ipareplica_setup_krb.py
+++ b/roles/ipareplica/library/ipareplica_setup_krb.py
@@ -96,7 +96,7 @@ def main():
             # additional
             config_master_host_name=dict(required=True),
             ccache=dict(required=True),
-            _pkinit_pkcs12_info=dict(required=False),
+            _pkinit_pkcs12_info=dict(required=False, type='list'),
             _top_dir=dict(required=True),
         ),
         supports_check_mode=True,
diff --git a/roles/ipareplica/tasks/install.yml b/roles/ipareplica/tasks/install.yml
index fe81a4d1d80b2fe00eb81f7acca41caffeada8b5..fc7f83e433dedd9172dc187ca86c2a089c8cc8fe 100644
--- a/roles/ipareplica/tasks/install.yml
+++ b/roles/ipareplica/tasks/install.yml
@@ -407,6 +407,7 @@
       ccache: "{{ result_ipareplica_prepare.ccache }}"
       _ca_enabled: "{{ result_ipareplica_prepare._ca_enabled }}"
       _ca_file: "{{ result_ipareplica_prepare._ca_file }}"
+      _dirsrv_pkcs12_info: "{{ result_ipareplica_prepare._dirsrv_pkcs12_info }}"
       _pkinit_pkcs12_info: "{{ result_ipareplica_prepare._pkinit_pkcs12_info }}"
       _top_dir: "{{ result_ipareplica_prepare._top_dir }}"
       dirman_password: "{{ ipareplica_dirman_password }}"
@@ -750,6 +751,16 @@
       state: absent
     when: result_ipareplica_enable_ipa.changed
 
+  always:
+  - name: Cleanup temporary files
+    file:
+      path: "{{ item }}"
+      state: absent
+    with_items:
+    - "/etc/ipa/.tmp_pkcs12_dirsrv"
+    - "/etc/ipa/.tmp_pkcs12_http"
+    - "/etc/ipa/.tmp_pkcs12_pkinit"
+
   when: not ansible_check_mode and
         not (result_ipareplica_test.client_already_configured is defined or
              result_ipareplica_test.server_already_configured is defined)
diff --git a/roles/ipaserver/library/ipaserver_set_ds_password.py b/roles/ipaserver/library/ipaserver_set_ds_password.py
index 007730241ed22b3d63bf728b588e89880cde7e4e..4b5b3b35ee3994aca8d69dc609bd82af16e4e309 100644
--- a/roles/ipaserver/library/ipaserver_set_ds_password.py
+++ b/roles/ipaserver/library/ipaserver_set_ds_password.py
@@ -127,7 +127,7 @@ def main():
             no_hbac_allow=dict(required=False, type='bool', default=False),
             no_pkinit=dict(required=False, type='bool', default=False),
             dirsrv_config_file=dict(required=False),
-            _dirsrv_pkcs12_info=dict(required=False),
+            _dirsrv_pkcs12_info=dict(required=False, type='list'),
             # ssl certificate
             dirsrv_cert_files=dict(required=False, type='list', default=[]),
             subject_base=dict(required=False),
diff --git a/roles/ipaserver/library/ipaserver_setup_ca.py b/roles/ipaserver/library/ipaserver_setup_ca.py
index faaf66018a7cbffcde3ead96d53fac88af258473..6a5cfcce45d2f9772603c6aaae9b9c153dbd1fe8 100644
--- a/roles/ipaserver/library/ipaserver_setup_ca.py
+++ b/roles/ipaserver/library/ipaserver_setup_ca.py
@@ -163,7 +163,7 @@ from ansible.module_utils.ansible_ipa_server import (
     AnsibleModuleLog, setup_logging, options, sysrestore, paths,
     ansible_module_get_parsed_ip_addresses,
     api_Backend_ldap2, redirect_stdout, ca, installutils, ds_init_info,
-    custodiainstance, write_cache, x509
+    custodiainstance, write_cache, x509, decode_certificate
 )
 
 
@@ -191,7 +191,7 @@ def main():
             no_pkinit=dict(required=False, type='bool', default=False),
             dirsrv_config_file=dict(required=False),
             dirsrv_cert_files=dict(required=False, type='list'),
-            _dirsrv_pkcs12_info=dict(required=False),
+            _dirsrv_pkcs12_info=dict(required=False, type='list'),
             # certificate system
             external_ca=dict(required=False, type='bool', default=False),
             external_ca_type=dict(required=False),
@@ -265,8 +265,8 @@ def main():
     # additional
     options.domainlevel = ansible_module.params.get('domainlevel')
     options._http_ca_cert = ansible_module.params.get('_http_ca_cert')
-    # tions._update_hosts_file = ansible_module.params.get(
-    #   'update_hosts_file')
+    if options._http_ca_cert is not None:
+        options._http_ca_cert = decode_certificate(options._http_ca_cert)
 
     # init #################################################################
 
diff --git a/roles/ipaserver/library/ipaserver_setup_ds.py b/roles/ipaserver/library/ipaserver_setup_ds.py
index fc49d62a246bcd23b12e7bdade8a3c0243244f00..3fc9d50ad2ceb3a6ba02d4f232b3021f97395346 100644
--- a/roles/ipaserver/library/ipaserver_setup_ds.py
+++ b/roles/ipaserver/library/ipaserver_setup_ds.py
@@ -126,7 +126,7 @@ def main():
             dirsrv_config_file=dict(required=False),
             # ssl certificate
             dirsrv_cert_files=dict(required=False, type='list', default=[]),
-            _dirsrv_pkcs12_info=dict(required=False),
+            _dirsrv_pkcs12_info=dict(required=False, type='list'),
             # certificate system
             external_cert_files=dict(required=False, type='list', default=[]),
             subject_base=dict(required=False),
diff --git a/roles/ipaserver/library/ipaserver_setup_http.py b/roles/ipaserver/library/ipaserver_setup_http.py
index f5479f5d152250a565fef71841aa21c02092ff54..4d9a54d6585f634c6850b5af321e1b85434da6fa 100644
--- a/roles/ipaserver/library/ipaserver_setup_http.py
+++ b/roles/ipaserver/library/ipaserver_setup_http.py
@@ -199,8 +199,8 @@ def main():
 
             # _update_hosts_file=dict(required=False, type='bool',
             #                         default=False),
-            _dirsrv_pkcs12_info=dict(required=False),
-            _http_pkcs12_info=dict(required=False),
+            _dirsrv_pkcs12_info=dict(required=False, type='list'),
+            _http_pkcs12_info=dict(required=False, type='list'),
         ),
     )
 
diff --git a/roles/ipaserver/library/ipaserver_setup_krb.py b/roles/ipaserver/library/ipaserver_setup_krb.py
index d86714672cff3864943aacaacb02a27ebcb212e2..1101d8d0cdf178583857b5deadac5179abccd351 100644
--- a/roles/ipaserver/library/ipaserver_setup_krb.py
+++ b/roles/ipaserver/library/ipaserver_setup_krb.py
@@ -160,7 +160,7 @@ def main():
             no_reverse=dict(required=False, type='bool', default=False),
             auto_forwarders=dict(required=False, type='bool', default=False),
 
-            _pkinit_pkcs12_info=dict(required=False),
+            _pkinit_pkcs12_info=dict(required=False, type='list'),
         ),
     )
 
diff --git a/roles/ipaserver/library/ipaserver_test.py b/roles/ipaserver/library/ipaserver_test.py
index 71afabcf6e7ee4b18ef0eb631e77af26da7ff9b7..4ac100c91d053f3ce188d38fa1fced725102c072 100644
--- a/roles/ipaserver/library/ipaserver_test.py
+++ b/roles/ipaserver/library/ipaserver_test.py
@@ -209,6 +209,7 @@ import sys
 import six
 import inspect
 import random
+from shutil import copyfile
 
 from ansible.module_utils.basic import AnsibleModule
 from ansible.module_utils._text import to_native
@@ -219,7 +220,8 @@ from ansible.module_utils.ansible_ipa_server import (
     NUM_VERSION, is_ipa_configured, sysrestore, paths, bindinstance,
     read_cache, ca, tasks, check_ldap_conf, timeconf, httpinstance,
     check_dirsrv, ScriptError, get_fqdn, verify_fqdn, BadHostError,
-    validate_domain_name, load_pkcs12, IPA_PYTHON_VERSION
+    validate_domain_name, load_pkcs12, IPA_PYTHON_VERSION,
+    encode_certificate
 )
 
 if six.PY3:
@@ -252,7 +254,7 @@ def main():
             dirsrv_config_file=dict(required=False),
             # ssl certificate
             dirsrv_cert_files=dict(required=False, type='list', default=None),
-            http_cert_files=dict(required=False, type='list', defaullt=None),
+            http_cert_files=dict(required=False, type='list', default=None),
             pkinit_cert_files=dict(required=False, type='list', default=None),
             dirsrv_pin=dict(required=False),
             http_pin=dict(required=False),
@@ -1013,6 +1015,21 @@ def main():
 
     # done ##################################################################
 
+    # Copy pkcs12_files to make them persistent till deployment is done
+    # and encode certificates for ansible compatibility
+    if http_pkcs12_info is not None:
+        copyfile(http_pkcs12_file.name, "/etc/ipa/.tmp_pkcs12_http")
+        http_pkcs12_info = ("/etc/ipa/.tmp_pkcs12_http", http_pin)
+        http_ca_cert = encode_certificate(http_ca_cert)
+    if dirsrv_pkcs12_info is not None:
+        copyfile(dirsrv_pkcs12_file.name, "/etc/ipa/.tmp_pkcs12_dirsrv")
+        dirsrv_pkcs12_info = ("/etc/ipa/.tmp_pkcs12_dirsrv", dirsrv_pin)
+        dirsrv_ca_cert = encode_certificate(dirsrv_ca_cert)
+    if pkinit_pkcs12_info is not None:
+        copyfile(pkinit_pkcs12_file.name, "/etc/ipa/.tmp_pkcs12_pkinit")
+        pkinit_pkcs12_info = ("/etc/ipa/.tmp_pkcs12_pkinit", pkinit_pin)
+        pkinit_ca_cert = encode_certificate(pkinit_ca_cert)
+
     ansible_module.exit_json(changed=False,
                              ipa_python_version=IPA_PYTHON_VERSION,
                              # basic
diff --git a/roles/ipaserver/module_utils/ansible_ipa_server.py b/roles/ipaserver/module_utils/ansible_ipa_server.py
index 244bc75d2ad99b524b18e17f31d68e337a939c8c..d934751389a33dfc8290e7e4133a36655bef0fd7 100644
--- a/roles/ipaserver/module_utils/ansible_ipa_server.py
+++ b/roles/ipaserver/module_utils/ansible_ipa_server.py
@@ -37,11 +37,13 @@ __all__ = ["IPAChangeConf", "certmonger", "sysrestore", "root_logger",
            "validate_dm_password", "read_cache", "write_cache",
            "adtrustinstance", "IPAAPI_USER", "sync_time", "PKIIniLoader",
            "default_subject_base", "default_ca_subject_dn",
-           "check_ldap_conf"]
+           "check_ldap_conf", "encode_certificate", "decode_certificate"]
 
 import sys
 import logging
 from contextlib import contextmanager as contextlib_contextmanager
+import six
+import base64
 
 
 from ipapython.version import NUM_VERSION, VERSION
@@ -137,6 +139,17 @@ if NUM_VERSION >= 40500:
     except ImportError:
         check_ldap_conf = None
 
+    try:
+        from ipalib.x509 import Encoding
+    except ImportError:
+        from cryptography.hazmat.primitives.serialization import Encoding
+
+    try:
+        from ipalib.x509 import load_pem_x509_certificate
+    except ImportError:
+        from ipalib.x509 import load_certificate
+        load_pem_x509_certificate = None
+
 else:
     # IPA version < 4.5
 
@@ -322,3 +335,41 @@ def ansible_module_get_parsed_ip_addresses(ansible_module,
             ansible_module.fail_json(msg="Invalid IP Address %s: %s" % (ip, e))
         ip_addrs.append(ip_parsed)
     return ip_addrs
+
+
+def encode_certificate(cert):
+    """
+    Encode a certificate using base64.
+
+    It also takes FreeIPA and Python versions into account.
+    """
+    if isinstance(cert, (str, bytes)):
+        encoded = base64.b64encode(cert)
+    else:
+        encoded = base64.b64encode(cert.public_bytes(Encoding.DER))
+    if not six.PY2:
+        encoded = encoded.decode('ascii')
+    return encoded
+
+
+def decode_certificate(cert):
+    """
+    Decode a certificate using base64.
+
+    It also takes FreeIPA versions into account and returns a IPACertificate
+    for newer IPA versions.
+    """
+    if hasattr(x509, "IPACertificate"):
+        cert = cert.strip()
+        if not cert.startswith("-----BEGIN CERTIFICATE-----"):
+            cert = "-----BEGIN CERTIFICATE-----\n" + cert
+        if not cert.endswith("-----END CERTIFICATE-----"):
+            cert += "\n-----END CERTIFICATE-----"
+
+        if load_pem_x509_certificate is not None:
+            cert = load_pem_x509_certificate(cert.encode('utf-8'))
+        else:
+            cert = load_certificate(cert.encode('utf-8'))
+    else:
+        cert = base64.b64decode(cert)
+    return cert
diff --git a/roles/ipaserver/tasks/install.yml b/roles/ipaserver/tasks/install.yml
index 85df9a7dd92610a133be9dffc92aef4629837cfe..30f9da2102e074b9317397d9ad7fabf77a3fa380 100644
--- a/roles/ipaserver/tasks/install.yml
+++ b/roles/ipaserver/tasks/install.yml
@@ -286,6 +286,7 @@
       reverse_zones: "{{ result_ipaserver_prepare.reverse_zones }}"
       no_reverse: "{{ ipaserver_no_reverse }}"
       auto_forwarders: "{{ ipaserver_auto_forwarders }}"
+      _http_ca_cert: "{{ result_ipaserver_test._http_ca_cert }}"
     register: result_ipaserver_setup_ca
 
   - name: Copy /root/ipa.csr to "{{ inventory_hostname }}-ipa.csr"
@@ -448,6 +449,16 @@
 
     when: not result_ipaserver_setup_ca.csr_generated | bool
 
+  always:
+  - name: Cleanup temporary files
+    file:
+      path: "{{ item }}"
+      state: absent
+    with_items:
+    - "/etc/ipa/.tmp_pkcs12_dirsrv"
+    - "/etc/ipa/.tmp_pkcs12_http"
+    - "/etc/ipa/.tmp_pkcs12_pkinit"
+
   when: not ansible_check_mode and not
         (not result_ipaserver_test.changed and
          (result_ipaserver_test.client_already_configured is defined or
diff --git a/tests/ca-less/certificates/pkinit/extensions.conf b/tests/ca-less/certificates/pkinit/extensions.conf
new file mode 100644
index 0000000000000000000000000000000000000000..cbff73bef1ed6cf35caf01ec8347627155983b27
--- /dev/null
+++ b/tests/ca-less/certificates/pkinit/extensions.conf
@@ -0,0 +1,20 @@
+[kdc_cert]
+basicConstraints=CA:FALSE
+keyUsage=nonRepudiation,digitalSignature,keyEncipherment,keyAgreement
+extendedKeyUsage=1.3.6.1.5.2.3.5
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer
+issuerAltName=issuer:copy
+subjectAltName=otherName:1.3.6.1.5.2.2;SEQUENCE:kdc_princ_name
+
+[kdc_princ_name]
+realm=EXP:0,GeneralString:${ENV::REALM}
+principal_name=EXP:1,SEQUENCE:kdc_principal_seq
+
+[kdc_principal_seq]
+name_type=EXP:0,INTEGER:1
+name_string=EXP:1,SEQUENCE:kdc_principals
+
+[kdc_principals]
+princ1=GeneralString:krbtgt
+princ2=GeneralString:${ENV::REALM}
diff --git a/tests/ca-less/clean_up_certificates.yml b/tests/ca-less/clean_up_certificates.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ea8a4e8ee714efbe9dd95f792eb92d11964c6eda
--- /dev/null
+++ b/tests/ca-less/clean_up_certificates.yml
@@ -0,0 +1,15 @@
+---
+- name: Clean up certificates
+  hosts: localhost
+  gather_facts: false
+
+  tasks:
+  - name: Run generate-certificates.sh
+    command: >
+      /bin/bash
+      generate-certificates.sh delete "{{ item }}"
+    args:
+      chdir: "{{ playbook_dir }}"
+    with_items:
+      - "{{ groups.ipaserver[0] }}"
+      - "{{ groups.ipareplicas[0] }}"
\ No newline at end of file
diff --git a/tests/ca-less/generate-certificates.sh b/tests/ca-less/generate-certificates.sh
new file mode 100755
index 0000000000000000000000000000000000000000..e96d323ae4a932883d2bc574d1e1cea3305d9b1e
--- /dev/null
+++ b/tests/ca-less/generate-certificates.sh
@@ -0,0 +1,153 @@
+#!/usr/bin/env bash
+
+ROOT_CA_DIR="certificates/root-ca"
+DIRSRV_CERTS_DIR="certificates/dirsrv"
+HTTPD_CERTS_DIR="certificates/httpd"
+PKINIT_CERTS_DIR="certificates/pkinit"
+PKCS12_PASSWORD="SomePKCS12password"
+
+# generate_ipa_pkcs12_certificate \
+#    $cert_name $ipa_fqdn $certs_dir $root_ca_cert $root_ca_private_key extensions_file extensions_name
+function generate_ipa_pkcs12_certificate {
+
+    cert_name=$1
+    ipa_fqdn=$2
+    certs_dir=$3
+    root_ca_cert=$4
+    root_ca_private_key=$5
+    extensions_file=$6
+    extensions_name=$7
+
+    # Generate CSR and private key
+    openssl req -new -newkey rsa:4096 -nodes \
+        -subj "/C=US/ST=Test/L=Testing/O=Default/CN=${ipa_fqdn}" \
+        -keyout ${certs_dir}/private.key \
+        -out ${certs_dir}/request.csr
+
+    # Sign CSR to generate PEM certificate
+    if [ -z "${extensions_file}" ]; then
+        openssl x509 -req -days 365 -sha256 \
+            -CAcreateserial \
+            -CA ${root_ca_cert} \
+            -CAkey ${root_ca_private_key} \
+            -in ${certs_dir}/request.csr \
+            -out ${certs_dir}/cert.pem
+    else
+        openssl x509 -req -days 365 -sha256 \
+            -CAcreateserial \
+            -CA ${ROOT_CA_DIR}/cert.pem \
+            -CAkey ${ROOT_CA_DIR}/private.key \
+            -extfile ${extensions_file} \
+            -extensions ${extensions_name} \
+            -in ${certs_dir}/request.csr \
+            -out ${certs_dir}/cert.pem
+    fi
+
+    # Convert certificate to PKCS12 format
+    openssl pkcs12 -export \
+        -name ${cert_name} \
+        -certfile ${root_ca_cert} \
+        -in ${certs_dir}/cert.pem \
+        -inkey ${certs_dir}/private.key \
+        -passout "pass:${PKCS12_PASSWORD}" \
+        -out ${certs_dir}/cert.p12
+}
+
+# generate_ipa_pkcs12_certificates $ipa_fqdn $ipa_domain
+function generate_ipa_pkcs12_certificates {
+
+    host=$1
+    if [ -z "$host" ]; then
+        echo "ERROR: ipa-host-fqdn is not set"
+        echo
+        echo "usage: $0 create ipa-host-fqdn domain"
+        exit 0;
+    fi
+
+    domain=$2
+    if [ -z "$domain" ]; then
+        echo "ERROR: domain is not set"
+        echo
+        echo "usage: $0 create ipa-host-fqdn domain"
+        exit 0;
+    fi
+
+    # Generate certificates folder structure
+    mkdir -p ${ROOT_CA_DIR}
+    mkdir -p ${DIRSRV_CERTS_DIR}/$host
+    mkdir -p ${HTTPD_CERTS_DIR}/$host
+    mkdir -p ${PKINIT_CERTS_DIR}/$host
+
+    # Generate root CA
+    if [ ! -f "${ROOT_CA_DIR}/private.key" ]; then
+        openssl genrsa \
+                -out ${ROOT_CA_DIR}/private.key 4096
+
+        openssl req -new -x509 -sha256 -nodes -days 3650 \
+                -subj "/C=US/ST=Test/L=Testing/O=Default" \
+                -key ${ROOT_CA_DIR}/private.key \
+                -out ${ROOT_CA_DIR}/cert.pem
+    fi
+
+    # Generate a certificate for the Directory Server
+    if [ ! -f "${DIRSRV_CERTS_DIR}/$host/cert.pem" ]; then
+        generate_ipa_pkcs12_certificate \
+            "dirsrv-cert" \
+            $host \
+            "${DIRSRV_CERTS_DIR}/$host" \
+            "${ROOT_CA_DIR}/cert.pem" \
+            "${ROOT_CA_DIR}/private.key"
+    fi
+
+    # Generate a certificate for the Apache server
+    if [ ! -f "${HTTPD_CERTS_DIR}/$host/cert.pem" ]; then
+        generate_ipa_pkcs12_certificate \
+            "httpd-cert" \
+            $host \
+            "${HTTPD_CERTS_DIR}/$host" \
+            "${ROOT_CA_DIR}/cert.pem" \
+            "${ROOT_CA_DIR}/private.key"
+    fi
+
+    # Generate a certificate for the KDC PKINIT
+    if [ ! -f "${PKINIT_CERTS_DIR}/$host/cert.pem" ]; then
+        export REALM=${domain^^}
+
+        generate_ipa_pkcs12_certificate \
+            "pkinit-cert" \
+            $host \
+            "${PKINIT_CERTS_DIR}/$host" \
+            "${ROOT_CA_DIR}/cert.pem" \
+            "${ROOT_CA_DIR}/private.key" \
+            "${PKINIT_CERTS_DIR}/extensions.conf" \
+            "kdc_cert"
+    fi
+}
+
+# delete_ipa_pkcs12_certificates $ipa_fqdn
+function delete_ipa_pkcs12_certificates {
+
+    host=$1
+    if [ -z "$host" ]; then
+        echo "ERROR: ipa-host-fqdn is not set"
+        echo
+        echo "usage: $0 delete ipa-host-fqdn"
+        exit 0;
+    fi
+
+    rm -f certificates/*/$host/*
+    rm -f ${ROOT_CA_DIR}/*
+}
+
+# Entrypoint
+case "$1" in
+  create)
+    generate_ipa_pkcs12_certificates $2 $3
+    ;;
+  delete)
+    delete_ipa_pkcs12_certificates $2
+    ;;
+  *)
+    echo $"Usage: $0 {create|delete}"
+    ;;
+esac
diff --git a/tests/ca-less/install_replica_without_ca.yml b/tests/ca-less/install_replica_without_ca.yml
new file mode 100644
index 0000000000000000000000000000000000000000..83398b24596cc9be52b156d9d27ec1ff8fc4f18e
--- /dev/null
+++ b/tests/ca-less/install_replica_without_ca.yml
@@ -0,0 +1,82 @@
+---
+- name: Generate certificates
+  hosts: localhost
+  gather_facts: false
+
+  tasks:
+  - name: Run generate-certificates.sh
+    command: >
+      /bin/bash
+      generate-certificates.sh create
+      "{{ groups.ipareplicas[0] }}"
+      "{{ ipareplica_domain | default(groups.ipareplicas[0].split('.')[1:] | join ('.')) }}"
+    args:
+      chdir: "{{ playbook_dir }}"
+
+- name: Test ipareplicas installation without CA
+  hosts: ipareplicas
+  become: true
+
+  vars:
+    # Root CA certificate
+    ipareplica_ca_cert_files:
+      - /root/ca-less-test/ca.crt
+    # Directory server certificates
+    ipareplica_dirsrv_cert_name: dirsrv-cert
+    ipareplica_dirsrv_cert_files:
+      - /root/ca-less-test/dirsrv.p12
+    ipareplica_dirsrv_pin: SomePKCS12password
+    # Apache certificates
+    ipareplica_http_cert_name: httpd-cert
+    ipareplica_http_cert_files:
+      - /root/ca-less-test/httpd.p12
+    ipareplica_http_pin: SomePKCS12password
+    # PKINIT configuration
+    ipareplica_no_pkinit: no
+    ipareplica_pkinit_cert_name: pkinit-cert
+    ipareplica_pkinit_cert_files:
+      - /root/ca-less-test/pkinit.p12
+    ipareplica_pkinit_pin: SomePKCS12password
+
+  pre_tasks:
+    - name: Remove "/root/ca-less-test"
+      file:
+        path: "/root/ca-less-test"
+        state: absent
+
+    - name: Generate "/root/ca-less-test"
+      file:
+        path: "/root/ca-less-test"
+        state: directory
+
+    - name: Copy CA certificate
+      copy:
+        src: "{{ playbook_dir }}/certificates/root-ca/cert.pem"
+        dest: "/root/ca-less-test/ca.crt"
+        owner: root
+        group: root
+        mode: "0644"
+
+    - name: Copy p12 certificates
+      copy:
+        src: "{{ playbook_dir }}/certificates/{{ item }}/{{ groups.ipareplicas[0] }}/cert.p12"
+        dest: "/root/ca-less-test/{{ item }}.p12"
+        owner: root
+        group: root
+        mode: "0644"
+      with_items:
+        - dirsrv
+        - httpd
+        - pkinit
+
+  roles:
+    - role: ipareplica
+      state: present
+
+  post_tasks:
+    - name: Fix KDC certificate permissions
+      file:
+        path: /var/kerberos/krb5kdc/kdc.crt
+        owner: root
+        group: root
+        mode: '0644'
diff --git a/tests/ca-less/install_server_without_ca.yml b/tests/ca-less/install_server_without_ca.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ecb609c4fd17593e0352a5b2c37c28465266e394
--- /dev/null
+++ b/tests/ca-less/install_server_without_ca.yml
@@ -0,0 +1,74 @@
+---
+- name: Generate certificates
+  hosts: localhost
+  gather_facts: false
+
+  tasks:
+  - name: Run generate-certificates.sh
+    command: >
+      /bin/bash
+      generate-certificates.sh create
+      "{{ groups.ipaserver[0] }}"
+      "{{ ipaserver_domain | default(groups.ipaserver[0].split('.')[1:] | join ('.')) }}"
+    args:
+      chdir: "{{ playbook_dir }}"
+
+- name: Test ipaserver installation without CA
+  hosts: ipaserver
+  become: true
+
+  vars:
+    # Root CA certificate
+    ipaserver_ca_cert_files:
+      - /root/ca-less-test/ca.crt
+    # Directory server certificates
+    ipaserver_dirsrv_cert_name: dirsrv-cert
+    ipaserver_dirsrv_cert_files:
+      - /root/ca-less-test/dirsrv.p12
+    ipaserver_dirsrv_pin: SomePKCS12password
+    # Apache certificates
+    ipaserver_http_cert_name: httpd-cert
+    ipaserver_http_cert_files:
+      - /root/ca-less-test/httpd.p12
+    ipaserver_http_pin: SomePKCS12password
+    # PKINIT configuration
+    ipaserver_no_pkinit: no
+    ipaserver_pkinit_cert_name: pkinit-cert
+    ipaserver_pkinit_cert_files:
+      - /root/ca-less-test/pkinit.p12
+    ipaserver_pkinit_pin: SomePKCS12password
+
+  pre_tasks:
+    - name: Remove "/root/ca-less-test"
+      file:
+        path: "/root/ca-less-test"
+        state: absent
+
+    - name: Generate "/root/ca-less-test"
+      file:
+        path: "/root/ca-less-test"
+        state: directory
+
+    - name: Copy CA certificate
+      copy:
+        src: "{{ playbook_dir }}/certificates/root-ca/cert.pem"
+        dest: "/root/ca-less-test/ca.crt"
+        owner: root
+        group: root
+        mode: "0644"
+
+    - name: Copy p12 certificates
+      copy:
+        src: "{{ playbook_dir }}/certificates/{{ item }}/{{ groups.ipaserver[0] }}/cert.p12"
+        dest: "/root/ca-less-test/{{ item }}.p12"
+        owner: root
+        group: root
+        mode: "0644"
+      with_items:
+        - dirsrv
+        - httpd
+        - pkinit
+
+  roles:
+    - role: ipaserver
+      state: present
diff --git a/tests/ca-less/inventory b/tests/ca-less/inventory
new file mode 100644
index 0000000000000000000000000000000000000000..ec5da4ef66fe5601863f805f0fbf32bea9c6b999
--- /dev/null
+++ b/tests/ca-less/inventory
@@ -0,0 +1,17 @@
+[ipaserver]
+ipaserver.test.local
+
+[ipaserver:vars]
+ipaserver_domain=test.local
+ipaserver_realm=TEST.LOCAL
+ipaadmin_password=SomeADMINpassword
+ipadm_password=SomeDMpassword
+
+[ipareplicas]
+ipareplica.test.local
+
+[ipareplicas:vars]
+ipareplica_domain=test.local
+ipareplica_realm=TEST.LOCAL
+ipaadmin_password=SomeADMINpassword
+ipadm_password=SomeDMpassword
\ No newline at end of file