diff --git a/core/src/main/java/org/jboss/intersmash/annotations/Intersmash.java b/core/src/main/java/org/jboss/intersmash/annotations/Intersmash.java
index 6175b9c1a..32a3ab76b 100644
--- a/core/src/main/java/org/jboss/intersmash/annotations/Intersmash.java
+++ b/core/src/main/java/org/jboss/intersmash/annotations/Intersmash.java
@@ -23,6 +23,10 @@
 import org.jboss.intersmash.junit5.IntersmashExtension;
 import org.junit.jupiter.api.extension.ExtendWith;
 
+/**
+ * Annotation that is applied to a test class, so that the JUnit engine would use the {@link IntersmashExtension} to
+ * run the Intersmash provisioning workflow, and execute the related tests.
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.TYPE)
 @ExtendWith(IntersmashExtension.class)
diff --git a/core/src/main/java/org/jboss/intersmash/annotations/Service.java b/core/src/main/java/org/jboss/intersmash/annotations/Service.java
index 80797fc1d..5382629a7 100644
--- a/core/src/main/java/org/jboss/intersmash/annotations/Service.java
+++ b/core/src/main/java/org/jboss/intersmash/annotations/Service.java
@@ -23,6 +23,10 @@
 
 import org.jboss.intersmash.application.Application;
 
+/**
+ * Annotation to define an Intersmash service, i.e. the abstraction of a given runtime workload.
+ * Examples are: a WildFly application service, a Keycloak service etc. on OpenShift.
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.TYPE)
 @Repeatable(Services.class)
diff --git a/core/src/main/java/org/jboss/intersmash/annotations/Services.java b/core/src/main/java/org/jboss/intersmash/annotations/Services.java
index 5e15d421a..147dade0e 100644
--- a/core/src/main/java/org/jboss/intersmash/annotations/Services.java
+++ b/core/src/main/java/org/jboss/intersmash/annotations/Services.java
@@ -20,6 +20,9 @@
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+/**
+ * Annotation to define a group of Intersmash {@link Service} instances.
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.TYPE)
 public @interface Services {
diff --git a/core/src/main/java/org/jboss/intersmash/junit5/IntersmashExecutionCondition.java b/core/src/main/java/org/jboss/intersmash/junit5/IntersmashExecutionCondition.java
index d08f9c506..98ccc1487 100644
--- a/core/src/main/java/org/jboss/intersmash/junit5/IntersmashExecutionCondition.java
+++ b/core/src/main/java/org/jboss/intersmash/junit5/IntersmashExecutionCondition.java
@@ -29,6 +29,10 @@
 import cz.xtf.core.openshift.OpenShifts;
 import lombok.extern.slf4j.Slf4j;
 
+/**
+ * Implements a JUnit {@link ExecutionCondition} that is used to control whether a test class workflow can be managed by
+ * {@link IntersmashExtension}
+ */
 @Slf4j
 public class IntersmashExecutionCondition implements ExecutionCondition {
 
diff --git a/core/src/main/java/org/jboss/intersmash/junit5/IntersmashExtension.java b/core/src/main/java/org/jboss/intersmash/junit5/IntersmashExtension.java
index 1f4c722f6..32bec47df 100644
--- a/core/src/main/java/org/jboss/intersmash/junit5/IntersmashExtension.java
+++ b/core/src/main/java/org/jboss/intersmash/junit5/IntersmashExtension.java
@@ -47,6 +47,10 @@
 import cz.xtf.core.openshift.OpenShifts;
 import lombok.extern.slf4j.Slf4j;
 
+/**
+ * Intersmash JUnit extension that handles the process of provisioning a cross-product scenario before starting the
+ * test execution.
+ */
 @Slf4j
 public class IntersmashExtension implements BeforeAllCallback, AfterAllCallback, TestInstancePostProcessor {
 
diff --git a/core/src/main/java/org/jboss/intersmash/provision/Provisioner.java b/core/src/main/java/org/jboss/intersmash/provision/Provisioner.java
index 2ceff6e72..283d60f49 100644
--- a/core/src/main/java/org/jboss/intersmash/provision/Provisioner.java
+++ b/core/src/main/java/org/jboss/intersmash/provision/Provisioner.java
@@ -20,7 +20,7 @@
 import org.jboss.intersmash.application.Application;
 
 /**
- * Application provisioner for deploying and undeploying the application.
+ * Application provisioner for deploying and undeploying a service, represented by a given {@link Application} instance.
  */
 public interface Provisioner<T extends Application> {
 
diff --git a/core/src/main/java/org/jboss/intersmash/provision/ProvisionerFactory.java b/core/src/main/java/org/jboss/intersmash/provision/ProvisionerFactory.java
index 4577ca7ef..235facd0c 100644
--- a/core/src/main/java/org/jboss/intersmash/provision/ProvisionerFactory.java
+++ b/core/src/main/java/org/jboss/intersmash/provision/ProvisionerFactory.java
@@ -17,6 +17,10 @@
 
 import org.jboss.intersmash.application.Application;
 
+/**
+ * Define the contract for classes that return a suitable {@link Provisioner} for a given {@link Application} class.
+ * @param <T> The type of the {@link Provisioner} that the factory implementation shall return.
+ */
 public interface ProvisionerFactory<T extends Provisioner> {
 
 	/**
diff --git a/core/src/main/java/org/jboss/intersmash/provision/ProvisionerManager.java b/core/src/main/java/org/jboss/intersmash/provision/ProvisionerManager.java
index e21b81c32..e50678a63 100644
--- a/core/src/main/java/org/jboss/intersmash/provision/ProvisionerManager.java
+++ b/core/src/main/java/org/jboss/intersmash/provision/ProvisionerManager.java
@@ -19,8 +19,10 @@
 
 import org.jboss.intersmash.application.Application;
 
+/**
+ * Manager class to load the suitable {@link Provisioner} for a given {@link Application} instance, based on SPI.
+ */
 public class ProvisionerManager {
-
 	/**
 	 * Get application provisioner based on interfaces the application does implement.
 	 *
diff --git a/core/src/main/java/org/jboss/intersmash/provision/openshift/FailFastUtils.java b/core/src/main/java/org/jboss/intersmash/provision/openshift/FailFastUtils.java
index 4429506da..3ac36412d 100644
--- a/core/src/main/java/org/jboss/intersmash/provision/openshift/FailFastUtils.java
+++ b/core/src/main/java/org/jboss/intersmash/provision/openshift/FailFastUtils.java
@@ -22,6 +22,10 @@
 import cz.xtf.core.waiting.failfast.FailFastBuilder;
 import cz.xtf.core.waiting.failfast.FailFastCheck;
 
+/**
+ * Helper class that leverages the XTF library fail-fast APIs in methods that can be used to control the
+ * Intersmash provisioning workflow.
+ */
 public class FailFastUtils {
 	private static String[] failFastEventMessages = new String[] {
 			"Failed to pull image.*",
diff --git a/core/src/main/java/org/jboss/intersmash/provision/openshift/OpenShiftUtils.java b/core/src/main/java/org/jboss/intersmash/provision/openshift/OpenShiftUtils.java
index 90cec8a26..2869009e4 100644
--- a/core/src/main/java/org/jboss/intersmash/provision/openshift/OpenShiftUtils.java
+++ b/core/src/main/java/org/jboss/intersmash/provision/openshift/OpenShiftUtils.java
@@ -19,6 +19,10 @@
 
 import cz.xtf.core.openshift.OpenShift;
 
+/**
+ * Helper class that leverages the XTF library {@link OpenShift} APIs in methods that can be used to control the
+ * Intersmash provisioning workflow.
+ */
 public class OpenShiftUtils {
 	public static void deleteResourcesWithLabel(OpenShift openShift, String labelKey, String labelValue) {
 		openShift.deploymentConfigs().withLabel(labelKey, labelValue).delete();
diff --git a/core/src/main/java/org/jboss/intersmash/provision/openshift/WaitersUtil.java b/core/src/main/java/org/jboss/intersmash/provision/openshift/WaitersUtil.java
index 904eba2eb..49966871d 100644
--- a/core/src/main/java/org/jboss/intersmash/provision/openshift/WaitersUtil.java
+++ b/core/src/main/java/org/jboss/intersmash/provision/openshift/WaitersUtil.java
@@ -28,6 +28,10 @@
 import io.fabric8.kubernetes.api.model.EndpointSubset;
 import io.fabric8.kubernetes.api.model.Endpoints;
 
+/**
+ * Helper class that leverages the XTF library {@link Waiter} APIs in methods that can be used to control the
+ * Intersmash provisioning workflow.
+ */
 public class WaitersUtil {
 	public static Waiter serviceEndpointsAreReady(OpenShift openShift, String serviceName, int numOfPods, Integer... ports) {
 		return new SimpleWaiter(() -> {
diff --git a/core/src/main/java/org/jboss/intersmash/provision/openshift/operator/resources/CatalogSource.java b/core/src/main/java/org/jboss/intersmash/provision/openshift/operator/resources/CatalogSource.java
index 78e782fe1..e375d4b94 100644
--- a/core/src/main/java/org/jboss/intersmash/provision/openshift/operator/resources/CatalogSource.java
+++ b/core/src/main/java/org/jboss/intersmash/provision/openshift/operator/resources/CatalogSource.java
@@ -17,6 +17,9 @@
 
 import io.fabric8.openshift.api.model.operatorhub.v1alpha1.CatalogSourceBuilder;
 
+/**
+ * Wrapper for creating and using {@link io.fabric8.openshift.api.model.operatorhub.v1alpha1.CatalogSource}
+ */
 public class CatalogSource extends io.fabric8.openshift.api.model.operatorhub.v1alpha1.CatalogSource
 		implements OpenShiftResource<CatalogSource> {
 
diff --git a/core/src/main/java/org/jboss/intersmash/provision/openshift/operator/resources/Subscription.java b/core/src/main/java/org/jboss/intersmash/provision/openshift/operator/resources/Subscription.java
index dfb3f8d96..db76c3cc6 100644
--- a/core/src/main/java/org/jboss/intersmash/provision/openshift/operator/resources/Subscription.java
+++ b/core/src/main/java/org/jboss/intersmash/provision/openshift/operator/resources/Subscription.java
@@ -25,10 +25,9 @@
 import io.fabric8.openshift.api.model.operatorhub.v1alpha1.SubscriptionFluent;
 
 /**
- * <p>
  * The Subscription configures when and how to update a ClusterService, binds a ClusterService to a channel in a
  * CatalogSource and configures the update strategy for a ClusterService (automatic, manual approval, etc).
- * </p>
+ *
  * <p>This class is a wrapper for {@link io.fabric8.openshift.api.model.operatorhub.v1alpha1.Subscription} which
  * adds some capabilities</p>
  * <p>
diff --git a/core/src/main/java/org/jboss/intersmash/util/CommandLineBasedKeystoreGenerator.java b/core/src/main/java/org/jboss/intersmash/util/CommandLineBasedKeystoreGenerator.java
new file mode 100644
index 000000000..083653d37
--- /dev/null
+++ b/core/src/main/java/org/jboss/intersmash/util/CommandLineBasedKeystoreGenerator.java
@@ -0,0 +1,347 @@
+/**
+ * Copyright (C) 2023 Red Hat, Inc.
+ *
+ * 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.
+ */
+package org.jboss.intersmash.util;
+
+import java.io.BufferedReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Writer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import cz.xtf.core.config.OpenShiftConfig;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * CL based implementation of a class for generating keystores signed by one common generated Certification Authority
+ */
+@Slf4j
+public class CommandLineBasedKeystoreGenerator {
+	public static final String KEYSTORE_FILE_EXTENSION = ".keystore";
+	private static Path TMP_DIRECTORY = Paths.get("tmp").toAbsolutePath().resolve("keystores");
+	@Getter
+	private static Path caDir;
+	@Getter
+	private static Path truststore;
+	@Getter
+	private static final String password = "password";
+	private static final String INTERSMASH_CA = "Intersmash.ca";
+	private static final String TRUSTSTORE_FILE_NAME = "truststore";
+	public static final String CA_CERTIFICATE_PEM_FILE_NAME = "ca-certificate.pem";
+
+	/**
+	 * Statically set everything up in order to have private key, certificate and truststore ready
+	 */
+	static {
+		try {
+			TMP_DIRECTORY.toFile().mkdirs();
+			caDir = Files.createTempDirectory(TMP_DIRECTORY, "ca");
+			// Generate key and cert
+			processCall(caDir, "openssl",
+					"req",
+					"-new",
+					"-newkey",
+					"rsa:4096",
+					"-x509",
+					"-keyout",
+					"ca-key.pem",
+					"-out",
+					CA_CERTIFICATE_PEM_FILE_NAME,
+					"-days",
+					"365",
+					"-passout",
+					"pass:" + password,
+					"-subj",
+					"/C=CZ/ST=CZ/L=Brno/O=QE/CN=" + INTERSMASH_CA);
+			// Generate truststore that includes the generated CA cert
+			processCall(caDir, "keytool",
+					"-import",
+					"-noprompt",
+					"-keystore",
+					TRUSTSTORE_FILE_NAME,
+					"-file",
+					CA_CERTIFICATE_PEM_FILE_NAME,
+					"-alias",
+					INTERSMASH_CA,
+					"-storepass",
+					password);
+			// Download and import the openshift server certs into the generated truststore
+			processCall(caDir, "/bin/sh",
+					"-c",
+					"echo \"Q\" | openssl s_client -connect " + getOpenShiftHostAndPort()
+							+ " -showcerts 2>/dev/null > serversOpenSslResponse");
+			processCall(caDir, "/bin/sh",
+					"-c",
+					getSplitCommandNameBasedOnOeratingSystem()
+							+ " -f serverCert -s serversOpenSslResponse '/^-----BEGIN CERTIFICATE-----$/' '{*}'");
+			processCall(caDir, "/bin/sh",
+					"-c",
+					"find . -type f -not -name \"serverCert00\" -name \"serverCert[0-9][0-9]\" -exec openssl x509 -in {} -out {}.pem \\;");
+			processCall(caDir, "/bin/sh",
+					"-c",
+					"find . -type f -name \"serverCert[0-9][0-9].pem\" -exec keytool -import -noprompt -keystore "
+							+ TRUSTSTORE_FILE_NAME + " -file {} -alias {} -storepass " + password + " \\;");
+			truststore = caDir.resolve(TRUSTSTORE_FILE_NAME);
+		} catch (IOException e) {
+			throw new IllegalStateException("Failed to initialize Intersmash CA", e);
+		}
+	}
+
+	public static Path generateKeystore(String hostname) {
+		return generateKeystore(hostname, null, hostname, false);
+	}
+
+	public static Path generateKeystore(String hostname, String keyAlias) {
+		return generateKeystore(hostname, null, keyAlias, false);
+	}
+
+	public static Path generateKeystore(String hostname, String keyAlias, boolean deleteCaFromKeyStore) {
+		return generateKeystore(hostname, null, keyAlias, deleteCaFromKeyStore);
+	}
+
+	public static Path generateKeystore(String hostname, String[] alternativeHostnames) {
+		return generateKeystore(hostname, alternativeHostnames, hostname, false);
+	}
+
+	public static Path generateKeystore(String hostname, String[] alternativeHostnames, String keyAlias,
+			boolean deleteCaFromKeyStore) {
+		final String keystore = hostname + KEYSTORE_FILE_EXTENSION;
+		if (caDir.resolve(keystore).toFile().exists()) {
+			return caDir.resolve(keystore);
+		}
+		processCall(caDir, "keytool",
+				"-genkeypair",
+				"-keyalg",
+				"RSA",
+				"-noprompt",
+				"-alias",
+				keyAlias,
+				"-dname",
+				"CN=" + hostname + ", OU=TF, O=XTF, L=Brno, S=CZ, C=CZ",
+				"-keystore",
+				keystore,
+				"-storepass",
+				password,
+				"-keypass",
+				password,
+				"-deststoretype",
+				"pkcs12");
+		processCall(caDir, "keytool",
+				"-keystore",
+				keystore,
+				"-certreq",
+				"-alias",
+				keyAlias,
+				"--keyalg",
+				"rsa",
+				"-file",
+				hostname + ".csr",
+				"-storepass",
+				password);
+		// When provided, injects Subject Alternative Names (SAN) within the certificate
+		if (alternativeHostnames != null && alternativeHostnames.length > 0) {
+			try {
+				Writer writer = new FileWriter(caDir.resolve(keyAlias + ".extensions").toFile());
+				writer.write("[ req_ext ]\n");
+				writer.write("subjectAltName = @alt_names\n");
+				writer.write("\n");
+				writer.write("[ alt_names ]\n");
+
+				writer.write("DNS.1 = " + hostname + "\n");
+				for (int i = 0; i < alternativeHostnames.length; ++i) {
+					writer.write("DNS." + (i + 2) + " = " + alternativeHostnames[i] + "\n");
+				}
+				writer.flush();
+				writer.close();
+				processCall(caDir, "openssl",
+						"x509",
+						"-req",
+						"-CA",
+						CA_CERTIFICATE_PEM_FILE_NAME,
+						"-CAkey",
+						"ca-key.pem",
+						"-in",
+						hostname + ".csr",
+						"-out", hostname + ".cer",
+						"-days", "365",
+						"-CAcreateserial",
+						"-passin",
+						"pass:" + password,
+						"-extfile",
+						keyAlias + ".extensions",
+						"-extensions",
+						"req_ext");
+			} catch (IOException e) {
+				throw new RuntimeException(e);
+			}
+		} else {
+			processCall(caDir, "openssl",
+					"x509",
+					"-req",
+					"-CA",
+					CA_CERTIFICATE_PEM_FILE_NAME,
+					"-CAkey",
+					"ca-key.pem",
+					"-in",
+					hostname + ".csr",
+					"-out",
+					hostname + ".cer",
+					"-days",
+					"365",
+					"-CAcreateserial",
+					"-passin",
+					"pass:" + password);
+		}
+		processCall(caDir, "keytool",
+				"-import",
+				"-noprompt",
+				"-keystore",
+				keystore,
+				"-file",
+				CA_CERTIFICATE_PEM_FILE_NAME,
+				"-alias",
+				INTERSMASH_CA,
+				"-storepass",
+				password);
+		processCall(caDir, "keytool",
+				"-import",
+				"-keystore",
+				keystore,
+				"-file",
+				hostname + ".cer",
+				"-alias",
+				keyAlias,
+				"-storepass", password);
+		if (deleteCaFromKeyStore) {
+			processCall(caDir, "keytool",
+					"-delete",
+					"-noprompt",
+					"-alias", INTERSMASH_CA,
+					"-keystore",
+					keystore,
+					"-storepass",
+					password);
+		}
+		return caDir.resolve(keystore);
+	}
+
+	public static GeneratedPaths generateCerts(String hostname) {
+		return generateCerts(hostname, null);
+	}
+
+	public static GeneratedPaths generateCerts(String hostname, String[] alternativeHostnames) {
+		final String keystore = hostname + KEYSTORE_FILE_EXTENSION;
+		generateKeystore(hostname, alternativeHostnames);
+		// export cert as CN.keystore.pem
+		processCall(caDir, "keytool",
+				"-exportcert",
+				"-rfc",
+				"-keystore",
+				keystore,
+				"-alias",
+				hostname,
+				"-storepass",
+				password,
+				"-file",
+				keystore + ".pem");
+		// convert to CN.keystore.keywithattrs.pem
+		processCall(caDir, "openssl",
+				"pkcs12",
+				"-in",
+				keystore,
+				"-nodes",
+				"-nocerts",
+				"-out",
+				keystore + ".keywithattrs.pem",
+				"-passin",
+				"pass:" + password);
+		// Remove the Bag attributes to CN.keystore.key.pem
+		processCall(caDir, "openssl",
+				"rsa",
+				"-in",
+				keystore + ".keywithattrs.pem",
+				"-out",
+				keystore + ".key.pem");
+		return new GeneratedPaths(
+				caDir.resolve(CA_CERTIFICATE_PEM_FILE_NAME),
+				caDir.resolve(TRUSTSTORE_FILE_NAME),
+				caDir.resolve(keystore),
+				caDir.resolve(keystore + ".key.pem"),
+				caDir.resolve(keystore + ".pem"));
+	}
+
+	private static String getOpenShiftHostAndPort() {
+		String server = OpenShiftConfig.url().replaceFirst("https://", "");
+		server = server.endsWith("/") ? server.substring(0, server.length() - 1) : server;
+		server = server.contains(":") ? server : server + ":443";
+		return server;
+	}
+
+	private static String getSplitCommandNameBasedOnOeratingSystem() {
+		return System.getProperty("os.name").toLowerCase().startsWith("mac") ? "gcsplit" : "csplit";
+	}
+
+	private static void processCall(Path cwd, String... args) {
+		ProcessBuilder pb = new ProcessBuilder(args);
+
+		pb.directory(cwd.toFile());
+		pb.redirectErrorStream(true);
+
+		int result = -1;
+		Process process = null;
+		try {
+			process = pb.start();
+			result = process.waitFor();
+			try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
+				while (reader.ready()) {
+					if (result == 0) {
+						log.debug(reader.readLine());
+					} else {
+						log.error(reader.readLine());
+					}
+				}
+			}
+		} catch (IOException | InterruptedException e) {
+			throw new IllegalStateException("Failed executing " + String.join(" ", args));
+		}
+		if (result != 0) {
+			throw new IllegalStateException("Failed executing " + String.join(" ", args));
+		}
+	}
+
+	/**
+	 * POJO to hold the path of the generated certs and stores
+	 */
+	public static class GeneratedPaths {
+		public Path caPem;
+		public Path truststore;
+		public Path keystore;
+		public Path keyPem;
+		public Path certPem;
+
+		public GeneratedPaths(final Path caPem, final Path truststore, final Path keystore, final Path keyPem,
+				final Path certPem) {
+			this.caPem = caPem;
+			this.truststore = truststore;
+			this.keystore = keystore;
+			this.keyPem = keyPem;
+			this.certPem = certPem;
+		}
+	}
+}
diff --git a/core/src/main/java/org/jboss/intersmash/util/ProcessKeystoreGenerator.java b/core/src/main/java/org/jboss/intersmash/util/ProcessKeystoreGenerator.java
deleted file mode 100644
index 59c517fa8..000000000
--- a/core/src/main/java/org/jboss/intersmash/util/ProcessKeystoreGenerator.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/**
- * Copyright (C) 2023 Red Hat, Inc.
- *
- * 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.
- */
-package org.jboss.intersmash.util;
-
-import java.io.BufferedReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.Writer;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-import cz.xtf.core.config.OpenShiftConfig;
-import lombok.Getter;
-import lombok.extern.slf4j.Slf4j;
-
-/**
- * Class for generating keystores signed by one common generated ca
- */
-@Slf4j
-public class ProcessKeystoreGenerator {
-
-	private static Path TMP_DIRECTORY = Paths.get("tmp").toAbsolutePath().resolve("keystores");
-
-	@Getter
-	private static Path caDir;
-
-	@Getter
-	private static Path truststore;
-
-	@Getter
-	private static final String password = "password";
-
-	static {
-		try {
-			TMP_DIRECTORY.toFile().mkdirs();
-			caDir = Files.createTempDirectory(TMP_DIRECTORY, "ca");
-
-			// Generate key and cert
-			processCall(caDir, "openssl", "req", "-new", "-newkey", "rsa:4096", "-x509", "-keyout", "ca-key.pem", "-out",
-					"ca-certificate.pem", "-days", "365", "-passout", "pass:" + password, "-subj",
-					"/C=CZ/ST=CZ/L=Brno/O=QE/CN=xtf.ca");
-
-			// Generate truststore with ca cert
-			processCall(caDir, "keytool", "-import", "-noprompt", "-keystore", "truststore", "-file", "ca-certificate.pem",
-					"-alias", "xtf.ca", "-storepass", password);
-
-			// Import openshift server certs to truststore
-			String server = OpenShiftConfig.url().replaceFirst("https://", "");
-			server = server.endsWith("/") ? server.substring(0, server.length() - 1) : server;
-			server = server.contains(":") ? server : server + ":443";
-
-			processCall(caDir, "/bin/sh", "-c",
-					"echo \"Q\" | openssl s_client -connect " + server + " -showcerts 2>/dev/null > serversOpenSslResponse");
-			String splitCmd = System.getProperty("os.name").toLowerCase().startsWith("mac") ? "gcsplit" : "csplit";
-			processCall(caDir, "/bin/sh", "-c",
-					splitCmd + " -f serverCert -s serversOpenSslResponse '/^-----BEGIN CERTIFICATE-----$/' '{*}'");
-
-			processCall(caDir, "/bin/sh", "-c",
-					"find . -type f -not -name \"serverCert00\" -name \"serverCert[0-9][0-9]\" -exec openssl x509 -in {} -out {}.pem \\;");
-			processCall(caDir, "/bin/sh", "-c",
-					"find . -type f -name \"serverCert[0-9][0-9].pem\" -exec keytool -import -noprompt -keystore truststore -file {} -alias {} -storepass "
-							+ password + " \\;");
-
-			truststore = caDir.resolve("truststore");
-		} catch (IOException e) {
-			throw new IllegalStateException("Failed to initialize CA", e);
-		}
-	}
-
-	public static Path generateKeystore(String hostname) {
-		return generateKeystore(hostname, null, hostname, false);
-	}
-
-	public static Path generateKeystore(String hostname, String keyAlias) {
-		return generateKeystore(hostname, null, keyAlias, false);
-	}
-
-	public static Path generateKeystore(String hostname, String keyAlias, boolean deleteCaFromKeyStore) {
-		return generateKeystore(hostname, null, keyAlias, deleteCaFromKeyStore);
-	}
-
-	public static Path generateKeystore(String hostname, String[] alternativeHostnames) {
-		return generateKeystore(hostname, alternativeHostnames, hostname, false);
-	}
-
-	public static Path generateKeystore(String hostname, String[] alternativeHostnames, String keyAlias,
-			boolean deleteCaFromKeyStore) {
-		String keystore = hostname + ".keystore";
-
-		if (caDir.resolve(keystore).toFile().exists()) {
-			return caDir.resolve(keystore);
-		}
-
-		processCall(caDir, "keytool", "-genkeypair", "-keyalg", "RSA", "-noprompt", "-alias", keyAlias, "-dname",
-				"CN=" + hostname + ", OU=TF, O=XTF, L=Brno, S=CZ, C=CZ", "-keystore", keystore, "-storepass", password,
-				"-keypass", password, "-deststoretype", "pkcs12");
-
-		processCall(caDir, "keytool", "-keystore", keystore, "-certreq", "-alias", keyAlias, "--keyalg", "rsa", "-file",
-				hostname + ".csr", "-storepass", password);
-
-		if (alternativeHostnames != null && alternativeHostnames.length > 0) {
-			try {
-				Writer writer = new FileWriter(caDir.resolve(keyAlias + ".extensions").toFile());
-				writer.write("[ req_ext ]\n");
-				writer.write("subjectAltName = @alt_names\n");
-				writer.write("\n");
-				writer.write("[ alt_names ]\n");
-
-				writer.write("DNS.1 = " + hostname + "\n");
-				for (int i = 0; i < alternativeHostnames.length; ++i) {
-					writer.write("DNS." + (i + 2) + " = " + alternativeHostnames[i] + "\n");
-				}
-				writer.flush();
-				writer.close();
-
-				processCall(caDir, "openssl", "x509", "-req", "-CA", "ca-certificate.pem", "-CAkey", "ca-key.pem", "-in",
-						hostname + ".csr", "-out", hostname + ".cer", "-days", "365", "-CAcreateserial", "-passin",
-						"pass:" + password, "-extfile", keyAlias + ".extensions", "-extensions", "req_ext");
-
-			} catch (IOException e) {
-				throw new RuntimeException(e);
-			}
-		} else {
-			processCall(caDir, "openssl", "x509", "-req", "-CA", "ca-certificate.pem", "-CAkey", "ca-key.pem", "-in",
-					hostname + ".csr", "-out", hostname + ".cer", "-days", "365", "-CAcreateserial", "-passin",
-					"pass:" + password);
-		}
-
-		processCall(caDir, "keytool", "-import", "-noprompt", "-keystore", keystore, "-file", "ca-certificate.pem", "-alias",
-				"xtf.ca", "-storepass", password);
-
-		processCall(caDir, "keytool", "-import", "-keystore", keystore, "-file", hostname + ".cer", "-alias", keyAlias,
-				"-storepass", password);
-
-		if (deleteCaFromKeyStore) {
-			processCall(caDir, "keytool", "-delete", "-noprompt", "-alias", "xtf.ca", "-keystore", keystore, "-storepass",
-					password);
-		}
-
-		return caDir.resolve(keystore);
-	}
-
-	public static CertPaths generateCerts(String hostname) {
-		return generateCerts(hostname, null);
-	}
-
-	public static CertPaths generateCerts(String hostname, String[] alternativeHostnames) {
-		String keystore = hostname + ".keystore";
-
-		generateKeystore(hostname, alternativeHostnames);
-
-		// export cert as CN.keystore.pem
-		processCall(caDir, "keytool", "-exportcert", "-rfc", "-keystore", keystore, "-alias", hostname, "-storepass", password,
-				"-file", keystore + ".pem");
-
-		// convert to CN.keystore.keywithattrs.pem
-		processCall(caDir, "openssl", "pkcs12", "-in", keystore, "-nodes", "-nocerts", "-out", keystore + ".keywithattrs.pem",
-				"-passin", "pass:" + password);
-
-		// Remove the Bag attributes to CN.keystore.key.pem
-		processCall(caDir, "openssl", "rsa", "-in", keystore + ".keywithattrs.pem", "-out", keystore + ".key.pem");
-
-		return new CertPaths(
-				caDir.resolve("ca-certificate.pem"),
-				caDir.resolve("truststore"),
-				caDir.resolve(keystore),
-				caDir.resolve(keystore + ".key.pem"),
-				caDir.resolve(keystore + ".pem"));
-	}
-
-	private static void processCall(Path cwd, String... args) {
-		ProcessBuilder pb = new ProcessBuilder(args);
-
-		pb.directory(cwd.toFile());
-		pb.redirectErrorStream(true);
-
-		int result = -1;
-		Process process = null;
-		try {
-			process = pb.start();
-			result = process.waitFor();
-			try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
-				while (reader.ready()) {
-					if (result == 0) {
-						log.debug(reader.readLine());
-					} else {
-						log.error(reader.readLine());
-					}
-				}
-			}
-		} catch (IOException | InterruptedException e) {
-			throw new IllegalStateException("Failed executing " + String.join(" ", args));
-		}
-
-		if (result != 0) {
-			throw new IllegalStateException("Failed executing " + String.join(" ", args));
-		}
-	}
-
-	public static class CertPaths {
-
-		public Path caPem;
-		public Path truststore;
-		public Path keystore;
-		public Path keyPem;
-		public Path certPem;
-
-		public CertPaths(Path caPem, Path truststore, Path keystore, Path keyPem, Path certPem) {
-			this.caPem = caPem;
-			this.truststore = truststore;
-			this.keystore = keystore;
-			this.keyPem = keyPem;
-			this.certPem = certPem;
-		}
-	}
-}
diff --git a/core/src/main/resources/META-INF/services/org.jboss.intersmash.provision.ProvisionerFactory b/core/src/main/resources/META-INF/services/org.jboss.intersmash.provision.ProvisionerFactory
deleted file mode 100644
index 2ea1bd0ce..000000000
--- a/core/src/main/resources/META-INF/services/org.jboss.intersmash.provision.ProvisionerFactory
+++ /dev/null
@@ -1 +0,0 @@
-org.jboss.intersmash.provision.openshift.auto.OpenShiftAutoProvisionerFactory
diff --git a/provisioners/README.md b/provisioners/README.md
index 8e32d4226..bf1fa97ec 100644
--- a/provisioners/README.md
+++ b/provisioners/README.md
@@ -245,7 +245,7 @@ Automatic (or application dictated) provisioning is a way to delegate the whole
 Having a concrete instance of an Application class that implements interface
 _AutoProvisioningOpenShiftApplication_ will let the user add methods that map to the
 provisioning process workflow, e.g.: `deploy`, `scale`, `undeploy`.
-[OpenShiftAutoProvisionerFactory](../core/src/main/java/org/jboss/intersmash/provision/openshift/auto/OpenShiftAutoProvisionerFactory.java)
+[OpenShiftAutoProvisionerFactory](src/main/java/org/jboss/intersmash/provision/openshift/auto/OpenShiftAutoProvisionerFactory.java)
 provides a reference to a _Provisioner_ and _Application_ implementing this feature.
 
 A list of provisioners by product can be found [here](../docs/Provisioner-by-Product.md).
diff --git a/core/src/main/java/org/jboss/intersmash/application/auto/AutoProvisioningExecutionException.java b/provisioners/src/main/java/org/jboss/intersmash/application/auto/AutoProvisioningExecutionException.java
similarity index 100%
rename from core/src/main/java/org/jboss/intersmash/application/auto/AutoProvisioningExecutionException.java
rename to provisioners/src/main/java/org/jboss/intersmash/application/auto/AutoProvisioningExecutionException.java
diff --git a/core/src/main/java/org/jboss/intersmash/application/openshift/AutoProvisioningOpenShiftApplication.java b/provisioners/src/main/java/org/jboss/intersmash/application/openshift/AutoProvisioningOpenShiftApplication.java
similarity index 100%
rename from core/src/main/java/org/jboss/intersmash/application/openshift/AutoProvisioningOpenShiftApplication.java
rename to provisioners/src/main/java/org/jboss/intersmash/application/openshift/AutoProvisioningOpenShiftApplication.java
diff --git a/core/src/main/java/org/jboss/intersmash/provision/auto/AutoProvisioningManagedException.java b/provisioners/src/main/java/org/jboss/intersmash/provision/auto/AutoProvisioningManagedException.java
similarity index 100%
rename from core/src/main/java/org/jboss/intersmash/provision/auto/AutoProvisioningManagedException.java
rename to provisioners/src/main/java/org/jboss/intersmash/provision/auto/AutoProvisioningManagedException.java
diff --git a/core/src/main/java/org/jboss/intersmash/provision/openshift/auto/OpenShiftAutoProvisioner.java b/provisioners/src/main/java/org/jboss/intersmash/provision/openshift/auto/OpenShiftAutoProvisioner.java
similarity index 100%
rename from core/src/main/java/org/jboss/intersmash/provision/openshift/auto/OpenShiftAutoProvisioner.java
rename to provisioners/src/main/java/org/jboss/intersmash/provision/openshift/auto/OpenShiftAutoProvisioner.java
diff --git a/core/src/main/java/org/jboss/intersmash/provision/openshift/auto/OpenShiftAutoProvisionerFactory.java b/provisioners/src/main/java/org/jboss/intersmash/provision/openshift/auto/OpenShiftAutoProvisionerFactory.java
similarity index 100%
rename from core/src/main/java/org/jboss/intersmash/provision/openshift/auto/OpenShiftAutoProvisionerFactory.java
rename to provisioners/src/main/java/org/jboss/intersmash/provision/openshift/auto/OpenShiftAutoProvisionerFactory.java
diff --git a/provisioners/src/main/resources/META-INF/services/org.jboss.intersmash.provision.ProvisionerFactory b/provisioners/src/main/resources/META-INF/services/org.jboss.intersmash.provision.ProvisionerFactory
index 5510c7640..95b263325 100644
--- a/provisioners/src/main/resources/META-INF/services/org.jboss.intersmash.provision.ProvisionerFactory
+++ b/provisioners/src/main/resources/META-INF/services/org.jboss.intersmash.provision.ProvisionerFactory
@@ -15,4 +15,5 @@ org.jboss.intersmash.provision.openshift.Eap7ImageOpenShiftProvisionerFactory
 org.jboss.intersmash.provision.openshift.Eap7LegacyS2iBuildTemplateProvisionerFactory
 org.jboss.intersmash.provision.openshift.Eap7TemplateOpenShiftProvisionerFactory
 org.jboss.intersmash.provision.openshift.HyperfoilOperatorProvisionerFactory
+org.jboss.intersmash.provision.openshift.auto.OpenShiftAutoProvisionerFactory
 
diff --git a/testsuite/integration-tests/src/test/java/org/jboss/intersmash/testsuite/provision/openshift/OpenShiftProvisionerTestBase.java b/testsuite/integration-tests/src/test/java/org/jboss/intersmash/testsuite/provision/openshift/OpenShiftProvisionerTestBase.java
index 92df4de89..d8f778866 100644
--- a/testsuite/integration-tests/src/test/java/org/jboss/intersmash/testsuite/provision/openshift/OpenShiftProvisionerTestBase.java
+++ b/testsuite/integration-tests/src/test/java/org/jboss/intersmash/testsuite/provision/openshift/OpenShiftProvisionerTestBase.java
@@ -54,11 +54,10 @@
 import org.jboss.intersmash.test.deployments.TestDeploymentProperties;
 import org.jboss.intersmash.test.deployments.WildflyDeploymentApplicationConfiguration;
 import org.jboss.intersmash.testsuite.IntersmashTestsuiteProperties;
-import org.jboss.intersmash.util.ProcessKeystoreGenerator;
+import org.jboss.intersmash.util.CommandLineBasedKeystoreGenerator;
 import org.jboss.intersmash.util.openshift.WildflyOpenShiftUtils;
 import org.jboss.intersmash.util.tls.CertificatesUtils;
 import org.jboss.intersmash.util.wildfly.Eap7CliScriptBuilder;
-import org.keycloak.k8s.v2alpha1.Keycloak;
 import org.keycloak.k8s.v2alpha1.keycloakspec.HostnameBuilder;
 import org.keycloak.k8s.v2alpha1.keycloakspec.HttpBuilder;
 import org.keycloak.k8s.v2alpha1.keycloakspec.IngressBuilder;
@@ -105,9 +104,9 @@ public class OpenShiftProvisionerTestBase {
 	static RhSsoTemplateOpenShiftApplication getHttpsRhSso() {
 		return new RhSsoTemplateOpenShiftApplication() {
 			private final String secureAppHostname = "secure-" + getOpenShiftHostName();
-			private final Path keystore = ProcessKeystoreGenerator.generateKeystore(secureAppHostname);
+			private final Path keystore = CommandLineBasedKeystoreGenerator.generateKeystore(secureAppHostname);
 			private final String jceksFileName = "jgroups.jceks";
-			private final Path truststore = ProcessKeystoreGenerator.getTruststore();
+			private final Path truststore = CommandLineBasedKeystoreGenerator.getTruststore();
 
 			@Override
 			public String getName() {