-
Notifications
You must be signed in to change notification settings - Fork 216
Add Integration tests with Custom SSL IdentityStore/TrustSore #2282
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
cefcaa2
Inital check-in
7d35873
remove unused code
056ac20
Merge branch 'develop' of https://github.com/oracle/weblogic-kubernet…
d182a91
Typo in the javadoc
5c7dbec
Addressed review comments
beb533d
More review change
e0a1d01
Merge branch 'develop' of https://github.com/oracle/weblogic-kubernet…
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
228 changes: 228 additions & 0 deletions
228
integration-tests/src/test/java/oracle/weblogic/kubernetes/ItMiiCustomSslStore.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,228 @@ | ||
// Copyright (c) 2021, Oracle and/or its affiliates. | ||
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. | ||
|
||
package oracle.weblogic.kubernetes; | ||
|
||
import java.nio.file.Paths; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
import oracle.weblogic.kubernetes.annotations.IntegrationTest; | ||
import oracle.weblogic.kubernetes.annotations.Namespaces; | ||
import oracle.weblogic.kubernetes.logging.LoggingFacade; | ||
import org.awaitility.core.ConditionFactory; | ||
import org.junit.jupiter.api.BeforeAll; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.MethodOrderer; | ||
import org.junit.jupiter.api.Order; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.TestMethodOrder; | ||
|
||
import static java.util.concurrent.TimeUnit.MINUTES; | ||
import static java.util.concurrent.TimeUnit.SECONDS; | ||
import static oracle.weblogic.kubernetes.TestConstants.ADMIN_PASSWORD_DEFAULT; | ||
import static oracle.weblogic.kubernetes.TestConstants.ADMIN_USERNAME_DEFAULT; | ||
import static oracle.weblogic.kubernetes.TestConstants.DOMAIN_VERSION; | ||
import static oracle.weblogic.kubernetes.TestConstants.MII_BASIC_IMAGE_NAME; | ||
import static oracle.weblogic.kubernetes.TestConstants.MII_BASIC_IMAGE_TAG; | ||
import static oracle.weblogic.kubernetes.TestConstants.OCIR_SECRET_NAME; | ||
import static oracle.weblogic.kubernetes.TestConstants.RESULTS_ROOT; | ||
import static oracle.weblogic.kubernetes.actions.ActionConstants.MODEL_DIR; | ||
import static oracle.weblogic.kubernetes.actions.ActionConstants.RESOURCE_DIR; | ||
import static oracle.weblogic.kubernetes.actions.TestActions.scaleCluster; | ||
import static oracle.weblogic.kubernetes.assertions.TestAssertions.domainExists; | ||
import static oracle.weblogic.kubernetes.utils.CommonMiiTestUtils.createDomainResourceWithLogHome; | ||
import static oracle.weblogic.kubernetes.utils.CommonMiiTestUtils.createDomainSecret; | ||
import static oracle.weblogic.kubernetes.utils.CommonMiiTestUtils.createJobToChangePermissionsOnPvHostPath; | ||
import static oracle.weblogic.kubernetes.utils.CommonTestUtils.checkPodReadyAndServiceExists; | ||
import static oracle.weblogic.kubernetes.utils.CommonTestUtils.createConfigMapAndVerify; | ||
import static oracle.weblogic.kubernetes.utils.CommonTestUtils.createOcirRepoSecret; | ||
import static oracle.weblogic.kubernetes.utils.CommonTestUtils.createPV; | ||
import static oracle.weblogic.kubernetes.utils.CommonTestUtils.createPVC; | ||
import static oracle.weblogic.kubernetes.utils.CommonTestUtils.createSecretForBaseImages; | ||
import static oracle.weblogic.kubernetes.utils.CommonTestUtils.installAndVerifyOperator; | ||
import static oracle.weblogic.kubernetes.utils.CommonTestUtils.runClientInsidePod; | ||
import static oracle.weblogic.kubernetes.utils.CommonTestUtils.runJavacInsidePod; | ||
import static oracle.weblogic.kubernetes.utils.FileUtils.copyFileToPod; | ||
import static oracle.weblogic.kubernetes.utils.SslUtils.generateJksStores; | ||
import static oracle.weblogic.kubernetes.utils.ThreadSafeLogger.getLogger; | ||
import static org.awaitility.Awaitility.with; | ||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; | ||
import static org.junit.jupiter.api.Assertions.assertNotNull; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
/** | ||
* This test class verifies usage of CustomIdentityCustomTrust on PV. | ||
* Create a MII domain with an attached persistent volume. | ||
* Configure custom identity and custom trust on server template | ||
* Enable SSL on server template with port 8002 (default 7002 does not work) | ||
* Put the IdentityKeyStore.jks and TrustKeyStore.jks on /shared directory | ||
* after administration server pod is started so that it can be accessible | ||
* from all managed server pods | ||
* Once all servers are started get the JNDI initial context using cluster | ||
* service URL with t3s protocol. | ||
* Repeat the same after scaling the cluster | ||
*/ | ||
|
||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) | ||
@DisplayName("Test verifies usage of CustomIdentityCustomTrust on PV") | ||
@IntegrationTest | ||
class ItMiiCustomSslStore { | ||
|
||
private static String opNamespace = null; | ||
private static String domainNamespace = null; | ||
private static ConditionFactory withStandardRetryPolicy = null; | ||
private static int replicaCount = 2; | ||
private static final String domainUid = "mii-custom-ssl"; | ||
private static String pvName = domainUid + "-pv"; | ||
private static String pvcName = domainUid + "-pvc"; | ||
private static final String adminServerPodName = domainUid + "-admin-server"; | ||
private static final String managedServerPrefix = domainUid + "-managed-server"; | ||
private static LoggingFacade logger = null; | ||
private static String cpUrl; | ||
|
||
/** | ||
* Install Operator. | ||
* Create domain resource definition. | ||
* @param namespaces list of namespaces created by the IntegrationTestWatcher by the | ||
* JUnit engine parameter resolution mechanism | ||
*/ | ||
@BeforeAll | ||
public static void initAll(@Namespaces(2) List<String> namespaces) { | ||
logger = getLogger(); | ||
// create standard, reusable retry/backoff policy | ||
withStandardRetryPolicy = with().pollDelay(2, SECONDS) | ||
.and().with().pollInterval(10, SECONDS) | ||
.atMost(5, MINUTES).await(); | ||
|
||
// get a new unique opNamespace | ||
logger.info("Creating unique namespace for Operator"); | ||
assertNotNull(namespaces.get(0), "Namespace list is null"); | ||
opNamespace = namespaces.get(0); | ||
|
||
logger.info("Creating unique namespace for Domain"); | ||
assertNotNull(namespaces.get(1), "Namespace list is null"); | ||
domainNamespace = namespaces.get(1); | ||
|
||
// Create the repo secret to pull the image | ||
// this secret is used only for non-kind cluster | ||
createOcirRepoSecret(domainNamespace); | ||
|
||
// install and verify operator | ||
installAndVerifyOperator(opNamespace, domainNamespace); | ||
|
||
// create secret for admin credentials | ||
logger.info("Create secret for admin credentials"); | ||
String adminSecretName = "weblogic-credentials"; | ||
assertDoesNotThrow(() -> createDomainSecret(adminSecretName, | ||
ADMIN_USERNAME_DEFAULT, ADMIN_PASSWORD_DEFAULT, domainNamespace), | ||
String.format("createSecret failed for %s", adminSecretName)); | ||
|
||
// create encryption secret | ||
logger.info("Create encryption secret"); | ||
String encryptionSecretName = "encryptionsecret"; | ||
assertDoesNotThrow(() -> createDomainSecret(encryptionSecretName, "weblogicenc", | ||
"weblogicenc", domainNamespace), | ||
String.format("createSecret failed for %s", encryptionSecretName)); | ||
|
||
String configMapName = "mii-ssl-configmap"; | ||
createConfigMapAndVerify( | ||
configMapName, domainUid, domainNamespace, | ||
Arrays.asList(MODEL_DIR + "/mii.ssl.yaml")); | ||
|
||
// this secret is used only for non-kind cluster | ||
createSecretForBaseImages(domainNamespace); | ||
|
||
// create PV, PVC for logs/data | ||
createPV(pvName, domainUid, ItMiiCustomSslStore.class.getSimpleName()); | ||
createPVC(pvName, pvcName, domainUid, domainNamespace); | ||
|
||
// create job to change permissions on PV hostPath | ||
createJobToChangePermissionsOnPvHostPath(pvName, pvcName, domainNamespace); | ||
|
||
// create the domain CR with a pre-defined configmap | ||
createDomainResourceWithLogHome(domainUid, domainNamespace, | ||
MII_BASIC_IMAGE_NAME + ":" + MII_BASIC_IMAGE_TAG, | ||
adminSecretName, OCIR_SECRET_NAME, encryptionSecretName, | ||
replicaCount, pvName, pvcName, "cluster-1", configMapName, null, false, false); | ||
|
||
// wait for the domain to exist | ||
logger.info("Check for domain custom resource in namespace {0}", domainNamespace); | ||
withStandardRetryPolicy | ||
.conditionEvaluationListener( | ||
condition -> logger.info("Waiting for domain {0} to be created in namespace {1} " | ||
+ "(elapsed time {2}ms, remaining time {3}ms)", | ||
domainUid, | ||
domainNamespace, | ||
condition.getElapsedTimeInMS(), | ||
condition.getRemainingTimeInMS())) | ||
.until(domainExists(domainUid, DOMAIN_VERSION, domainNamespace)); | ||
|
||
logger.info("Check admin service and pod {0} is created in namespace {1}", | ||
adminServerPodName, domainNamespace); | ||
checkPodReadyAndServiceExists(adminServerPodName, domainUid, domainNamespace); | ||
// Generate JKS Keystore using openssl before | ||
// managed server services and pods are ready | ||
generateJksStores(); | ||
assertDoesNotThrow(() -> copyFileToPod(domainNamespace, | ||
adminServerPodName, "", | ||
Paths.get(RESULTS_ROOT, "IdentityKeyStore.jks"), | ||
Paths.get("/shared/IdentityKeyStore.jks"))); | ||
assertDoesNotThrow(() -> copyFileToPod(domainNamespace, | ||
adminServerPodName, "", | ||
Paths.get(RESULTS_ROOT, "TrustKeyStore.jks"), | ||
Paths.get("/shared/TrustKeyStore.jks"))); | ||
|
||
for (int i = 1; i <= replicaCount; i++) { | ||
logger.info("Wait for managed server services and pods are created in namespace {0}", | ||
domainNamespace); | ||
checkPodReadyAndServiceExists(managedServerPrefix + i, domainUid, domainNamespace); | ||
} | ||
} | ||
|
||
/** | ||
* Verify a standalone java client can access JNDI Context inside a pod. | ||
* The client uses t3s cluster URL with custom SSL TrustStore on commandline | ||
*/ | ||
@Test | ||
@Order(1) | ||
@DisplayName("Verify JNDI Context can be accessed using t3s cluster URL") | ||
public void testMiiGetCustomSSLContext() { | ||
|
||
// build the standalone Client on Admin pod after rolling restart | ||
String destLocation = "/u01/SslTestClient.java"; | ||
assertDoesNotThrow(() -> copyFileToPod(domainNamespace, | ||
adminServerPodName, "", | ||
Paths.get(RESOURCE_DIR, "ssl", "SslTestClient.java"), | ||
Paths.get(destLocation))); | ||
runJavacInsidePod(adminServerPodName, domainNamespace, destLocation); | ||
|
||
runClientOnAdminPod(); | ||
|
||
boolean psuccess = assertDoesNotThrow(() -> | ||
scaleCluster(domainUid, domainNamespace, "cluster-1", 3), | ||
String.format("replica patching to 3 failed for domain %s in namespace %s", domainUid, domainNamespace)); | ||
assertTrue(psuccess, | ||
String.format("Cluster replica patching failed for domain %s in namespace %s", domainUid, domainNamespace)); | ||
checkPodReadyAndServiceExists(managedServerPrefix + "3", domainUid, domainNamespace); | ||
|
||
runClientOnAdminPod(); | ||
} | ||
|
||
// Run standalone client to get initial context using t3s cluster url | ||
private void runClientOnAdminPod() { | ||
|
||
StringBuffer extOpts = new StringBuffer(""); | ||
extOpts.append("-Dweblogic.security.SSL.ignoreHostnameVerification=true "); | ||
extOpts.append("-Dweblogic.security.SSL.trustedCAKeyStore=/shared/TrustKeyStore.jks "); | ||
extOpts.append("-Dweblogic.security.SSL.trustedCAKeyStorePassPhrase=changeit "); | ||
withStandardRetryPolicy | ||
.conditionEvaluationListener( | ||
condition -> logger.info("Wait for client to get Initial context " | ||
+ "(elapsed time {0}ms, remaining time {1}ms)", | ||
condition.getElapsedTimeInMS(), | ||
condition.getRemainingTimeInMS())) | ||
.until(runClientInsidePod(adminServerPodName, domainNamespace, | ||
"/u01", extOpts.toString() + " SslTestClient", "t3s://" + domainUid + "-cluster-cluster-1:8002")); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 51 additions & 0 deletions
51
integration-tests/src/test/java/oracle/weblogic/kubernetes/utils/SslUtils.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// Copyright (c) 2021, Oracle and/or its affiliates. | ||
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. | ||
|
||
package oracle.weblogic.kubernetes.utils; | ||
|
||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.nio.file.StandardCopyOption; | ||
|
||
import oracle.weblogic.kubernetes.actions.impl.primitive.Command; | ||
import oracle.weblogic.kubernetes.logging.LoggingFacade; | ||
|
||
import static oracle.weblogic.kubernetes.TestConstants.RESULTS_ROOT; | ||
import static oracle.weblogic.kubernetes.actions.ActionConstants.RESOURCE_DIR; | ||
import static oracle.weblogic.kubernetes.actions.impl.primitive.Command.defaultCommandParams; | ||
import static oracle.weblogic.kubernetes.utils.ThreadSafeLogger.getLogger; | ||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
/** | ||
* The SSL utility class for tests. | ||
*/ | ||
public class SslUtils { | ||
|
||
/** | ||
* Generate SSL KeyStore in JKS format. | ||
*/ | ||
public static void generateJksStores() { | ||
LoggingFacade logger = getLogger(); | ||
Path jksInstallPath = | ||
Paths.get(RESOURCE_DIR, "bash-scripts", "generate-selfsign-jks.sh"); | ||
String installScript = jksInstallPath.toString(); | ||
String command = | ||
String.format("%s %s", installScript, RESULTS_ROOT); | ||
logger.info("JKS Store creation command {0}", command); | ||
assertTrue(() -> Command.withParams( | ||
defaultCommandParams() | ||
.command(command) | ||
.redirect(false)) | ||
.execute()); | ||
|
||
// Copy the scripts to RESULTS_ROOT | ||
assertDoesNotThrow(() -> Files.copy( | ||
Paths.get(RESOURCE_DIR, "bash-scripts", "generate-selfsign-jks.sh"), | ||
Paths.get(RESULTS_ROOT, "generate-selfsign-jks.sh"), | ||
StandardCopyOption.REPLACE_EXISTING), | ||
"Copy generate-selfsign-jks.sh to RESULTS_ROOT failed"); | ||
} | ||
|
||
} |
58 changes: 58 additions & 0 deletions
58
integration-tests/src/test/resources/bash-scripts/generate-selfsign-jks.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
#!/bin/bash | ||
# Copyright (c) 2021, Oracle and/or its affiliates. | ||
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. | ||
|
||
|
||
# Usage: | ||
# | ||
# $0 [install-dir] | ||
|
||
# Define functions | ||
function generate_jks_stores { | ||
|
||
( cd $workdir; | ||
|
||
host=`hostname` | ||
|
||
openssl req -newkey rsa:2048 -days 1 \ | ||
-passout pass:changeit -passin pass:changeit \ | ||
-x509 -keyout cakey.pem -out cacert.pem \ | ||
-subj "/C=US/ST=NJ/L=Basking Ridge/O=QA/CN=${host}" | ||
|
||
#cakey.pem is the private key | ||
#cacert.pem is the public certificate | ||
|
||
openssl pkcs12 -export -in cacert.pem -inkey cakey.pem \ | ||
-passout pass:changeit -passin pass:changeit \ | ||
-out identity.p12 -name "mykey" | ||
|
||
keytool -importkeystore -destkeystore IdentityKeyStore.jks \ | ||
-deststorepass changeit -srckeystore identity.p12 \ | ||
-srcstoretype PKCS12 -srcstorepass changeit | ||
|
||
keytool -import -file cacert.pem -keystore TrustKeyStore.jks \ | ||
-storepass changeit -noprompt | ||
|
||
) | ||
|
||
} | ||
|
||
# MAIN | ||
workdir=${1:-`pwd`} | ||
|
||
if [ ! -d ${workdir} ]; then | ||
mkdir -p $workdir | ||
fi | ||
|
||
( cd $workdir; | ||
rm -rf *.pem *.der | ||
rm -rf TrustKeyStore.jks IdentityKeyStore.jks | ||
rm -rf *.p12 | ||
) | ||
generate_jks_stores ${workdir} | ||
|
||
( cd $workdir; | ||
rm -rf *.pem *.der | ||
rm -rf *.p12 | ||
) | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is JKS Keystore required before the managed server service and pods are ready? How do you control the keystore is copied before the managed server service and pods are ready?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I copy the file immediately after the admin pod is ready and before managed server is being started. That is why insert the copy command between admin server service check and managed server service check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there will be possible race condition. If the keystore is required before the managed server is started, then you can start the admin server first, then copy the files and start the managed servers. CheckPodReady() method only checks the status of the pod and does not control when to start the pod.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After admin server is started it takes few seconds to create the table/JKS files before introspector picks the managed server which takes a minutes to start the server. I also checks if the JMS Server MBean are in proper managed server before proceeding tests. If I see the failure in nightly I have to create a dummy WebLogic Pod to create the table before the domain starts.