From 8d0fb665a01ee83d922d102ea6ed9500be6f01fa Mon Sep 17 00:00:00 2001 From: Michael Edgar Date: Sat, 4 Mar 2023 02:28:17 +0800 Subject: [PATCH] [MGDSTRM-10764] Update Keycloak to version 21 for OpenShift 4.12 (#873) Signed-off-by: Michael Edgar --- systemtest/pom.xml | 17 +- .../framework/KeycloakInstance.java | 52 +---- .../systemtest/framework/LogCollector.java | 4 +- .../framework/SystemTestEnvironment.java | 2 +- .../operator/KeycloakOperatorManager.java | 219 +++++++++++++----- .../src/main/resources/keycloak-instance.yml | 26 +++ .../src/main/resources/keycloak-postgres.yml | 54 +++++ .../src/main/resources/keycloak-realm.yml | 22 ++ systemtest/src/main/resources/keycloak.yml | 49 ---- .../src/main/resources/log4j2.properties | 1 + .../bf2/systemtest/unit/SuiteUnitTest.java | 8 +- 11 files changed, 288 insertions(+), 166 deletions(-) create mode 100644 systemtest/src/main/resources/keycloak-instance.yml create mode 100644 systemtest/src/main/resources/keycloak-postgres.yml create mode 100644 systemtest/src/main/resources/keycloak-realm.yml delete mode 100644 systemtest/src/main/resources/keycloak.yml diff --git a/systemtest/pom.xml b/systemtest/pom.xml index e4fb8af2b..686e8b570 100644 --- a/systemtest/pom.xml +++ b/systemtest/pom.xml @@ -24,6 +24,12 @@ org.bf2 kas-fleetshard-test ${project.version} + + + org.jboss.slf4j + slf4j-jboss-logmanager + + io.quarkus @@ -65,6 +71,7 @@ systemtest false + true true @@ -72,12 +79,6 @@ - - maven-surefire-plugin - - !${it.skip} - - org.apache.maven.plugins maven-failsafe-plugin @@ -98,7 +99,11 @@ **/ST*.java **/*ST.java + ${it.skip} ${it.skip} + + org.jboss.logmanager.LogManager + false 3.0 diff --git a/systemtest/src/main/java/org/bf2/systemtest/framework/KeycloakInstance.java b/systemtest/src/main/java/org/bf2/systemtest/framework/KeycloakInstance.java index 590b1368e..368548ee3 100644 --- a/systemtest/src/main/java/org/bf2/systemtest/framework/KeycloakInstance.java +++ b/systemtest/src/main/java/org/bf2/systemtest/framework/KeycloakInstance.java @@ -1,26 +1,21 @@ package org.bf2.systemtest.framework; import io.fabric8.kubernetes.api.model.Secret; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import org.bf2.test.k8s.KubeClient; import java.nio.charset.StandardCharsets; import java.util.Base64; public class KeycloakInstance { - private static final Logger LOGGER = LogManager.getLogger(KeycloakInstance.class); + public static final String KEYCLOAK_SECRET_NAME = "sso-x509-https-secret"; public static final String KEYCLOAK_SECRET_CERT = "tls.crt"; - public static final String ADMIN_SECRET = "credential-example-keycloak"; + public static final String ADMIN_SECRET = "keycloak-initial-admin"; - private final int jwksExpireSeconds = 500; - private final int jwksRefreshSeconds = 400; private final String username; private final String password; private final String namespace; private final String httpsUri; - private final String httpUri; private String validIssuerUri; private String jwksEndpointUri; @@ -30,14 +25,12 @@ public class KeycloakInstance { private String fallbackUserNameClaim; private final String keycloakCert; - public KeycloakInstance(String namespace) { Secret secret = KubeClient.getInstance().client().secrets().inNamespace(namespace).withName(ADMIN_SECRET).get(); - this.username = new String(Base64.getDecoder().decode(secret.getData().get("ADMIN_USERNAME").getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8); - this.password = new String(Base64.getDecoder().decode(secret.getData().get("ADMIN_PASSWORD").getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8); + this.username = new String(Base64.getDecoder().decode(secret.getData().get("username").getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8); + this.password = new String(Base64.getDecoder().decode(secret.getData().get("password").getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8); this.namespace = namespace; - this.httpsUri = "keycloak." + namespace + ".svc:8443"; - this.httpUri = "keycloak-discovery." + namespace + ".svc:8080"; + this.httpsUri = "keycloak-service." + namespace + ".svc:8443"; this.validIssuerUri = "https://" + httpsUri + "/auth/realms/demo"; this.jwksEndpointUri = "https://" + httpsUri + "/auth/realms/demo/protocol/openid-connect/certs"; this.oauthTokenEndpointUri = "https://" + httpsUri + "/auth/realms/demo/protocol/openid-connect/token"; @@ -47,24 +40,6 @@ public KeycloakInstance(String namespace) { this.keycloakCert = readKeycloakCert(); } - public void setRealm(String realmName, boolean tlsEnabled) { - LOGGER.info("Replacing validIssuerUri: {} to pointing to {} realm", validIssuerUri, realmName); - LOGGER.info("Replacing jwksEndpointUri: {} to pointing to {} realm", jwksEndpointUri, realmName); - LOGGER.info("Replacing oauthTokenEndpointUri: {} to pointing to {} realm", oauthTokenEndpointUri, realmName); - - if (tlsEnabled) { - LOGGER.info("Using HTTPS endpoints"); - validIssuerUri = "https://" + httpsUri + "/auth/realms/" + realmName; - jwksEndpointUri = "https://" + httpsUri + "/auth/realms/" + realmName + "/protocol/openid-connect/certs"; - oauthTokenEndpointUri = "https://" + httpsUri + "/auth/realms/" + realmName + "/protocol/openid-connect/token"; - } else { - LOGGER.info("Using HTTP endpoints"); - validIssuerUri = "http://" + httpUri + "/auth/realms/" + realmName; - jwksEndpointUri = "http://" + httpUri + "/auth/realms/" + realmName + "/protocol/openid-connect/certs"; - oauthTokenEndpointUri = "http://" + httpUri + "/auth/realms/" + realmName + "/protocol/openid-connect/token"; - } - } - public String getUsername() { return username; } @@ -81,10 +56,6 @@ public String getHttpsUri() { return httpsUri; } - public String getHttpUri() { - return httpUri; - } - public String getValidIssuerUri() { return validIssuerUri; } @@ -133,14 +104,6 @@ public void setFallbackUserNameClaim(String fallbackUserNameClaim) { this.fallbackUserNameClaim = fallbackUserNameClaim; } - public int getJwksExpireSeconds() { - return jwksExpireSeconds; - } - - public int getJwksRefreshSeconds() { - return jwksRefreshSeconds; - } - public String getKeycloakCert() { return keycloakCert; } @@ -154,12 +117,9 @@ private String readKeycloakCert() { @Override public String toString() { return "KeycloakInstance{" + - "jwksExpireSeconds=" + jwksExpireSeconds + System.lineSeparator() + - ", jwksRefreshSeconds=" + jwksRefreshSeconds + System.lineSeparator() + - ", username='" + username + '\'' + System.lineSeparator() + + "username='" + username + '\'' + System.lineSeparator() + ", password='" + password + '\'' + System.lineSeparator() + ", httpsUri='" + httpsUri + '\'' + System.lineSeparator() + - ", httpUri='" + httpUri + '\'' + System.lineSeparator() + ", validIssuerUri='" + validIssuerUri + '\'' + System.lineSeparator() + ", jwksEndpointUri='" + jwksEndpointUri + '\'' + System.lineSeparator() + ", oauthTokenEndpointUri='" + oauthTokenEndpointUri + '\'' + System.lineSeparator() + diff --git a/systemtest/src/main/java/org/bf2/systemtest/framework/LogCollector.java b/systemtest/src/main/java/org/bf2/systemtest/framework/LogCollector.java index f964fc08c..64a1dba88 100644 --- a/systemtest/src/main/java/org/bf2/systemtest/framework/LogCollector.java +++ b/systemtest/src/main/java/org/bf2/systemtest/framework/LogCollector.java @@ -1,6 +1,7 @@ package org.bf2.systemtest.framework; import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodStatus; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.bf2.systemtest.operator.FleetShardOperatorManager; @@ -14,6 +15,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +import java.util.Optional; public class LogCollector { private static final Logger LOGGER = LogManager.getLogger(LogCollector.class); @@ -27,7 +29,7 @@ public static void saveKubernetesState(ExtensionContext extensionContext, Throwa LOGGER.info("Pod: {} in ns: {} with phase: {}", p.getMetadata().getName(), p.getMetadata().getNamespace(), - p.getStatus().getPhase())); + Optional.ofNullable(p.getStatus()).map(PodStatus::getPhase).orElse("null"))); Path logPath = TestUtils.getLogPath(Environment.LOG_DIR.resolve("failedTest").toString(), extensionContext); Files.createDirectories(logPath); diff --git a/systemtest/src/main/java/org/bf2/systemtest/framework/SystemTestEnvironment.java b/systemtest/src/main/java/org/bf2/systemtest/framework/SystemTestEnvironment.java index 04b8da6be..2e5e11520 100644 --- a/systemtest/src/main/java/org/bf2/systemtest/framework/SystemTestEnvironment.java +++ b/systemtest/src/main/java/org/bf2/systemtest/framework/SystemTestEnvironment.java @@ -59,7 +59,7 @@ public class SystemTestEnvironment extends Environment { public static final Path YAML_SYNC_BUNDLE_PATH = Environment.getOrDefault(YAML_SYNC_BUNDLE_PATH_ENV, Paths::get, Paths.get(ROOT_PATH.toString(), "sync", "target", "kubernetes", "kubernetes.yml")); public static final String FLEET_SHARD_PULL_SECRET_PATH = Environment.getOrDefault(FLEET_SHARD_PULL_SECRET_PATH_ENV, ""); - public static final String KEYCLOAK_VERSION = Environment.getOrDefault("KEYCLOAK_VERSION", "14.0.0"); + public static final String KEYCLOAK_VERSION = Environment.getOrDefault("KEYCLOAK_VERSION", "21.0.0"); public static final boolean INSTALL_KEYCLOAK = Environment.getOrDefault("INSTALL_KEYCLOAK", Boolean::parseBoolean, true); public static void logEnvironment() { diff --git a/systemtest/src/main/java/org/bf2/systemtest/operator/KeycloakOperatorManager.java b/systemtest/src/main/java/org/bf2/systemtest/operator/KeycloakOperatorManager.java index 432035c26..2deb6ca8d 100644 --- a/systemtest/src/main/java/org/bf2/systemtest/operator/KeycloakOperatorManager.java +++ b/systemtest/src/main/java/org/bf2/systemtest/operator/KeycloakOperatorManager.java @@ -1,104 +1,205 @@ package org.bf2.systemtest.operator; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.api.model.Namespace; import io.fabric8.kubernetes.api.model.NamespaceBuilder; -import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.api.model.SecretBuilder; +import io.fabric8.kubernetes.api.model.batch.v1.Job; +import io.fabric8.kubernetes.api.model.batch.v1.JobStatus; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.dsl.Gettable; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.bf2.systemtest.framework.KeycloakInstance; import org.bf2.systemtest.framework.SecurityUtils; import org.bf2.systemtest.framework.SystemTestEnvironment; -import org.bf2.test.Environment; import org.bf2.test.TestUtils; import org.bf2.test.k8s.KubeClient; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.nio.file.Paths; -import java.util.Arrays; import java.util.Base64; +import java.util.Collection; +import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; public class KeycloakOperatorManager { private static final Logger LOGGER = LogManager.getLogger(KeycloakOperatorManager.class); public static final String OPERATOR_NS = "kas-fleetshard-keycloak"; + private static final String KC_NAME = "keycloak"; + private static final String KEYCLOAK_RESOURCE_BASEURL = String.format("https://raw.githubusercontent.com/keycloak/keycloak-k8s-resources/%s/kubernetes/", SystemTestEnvironment.KEYCLOAK_VERSION); private static final List INSTALLED_RESOURCES = new LinkedList<>(); public static CompletableFuture installKeycloak(KubeClient kubeClient) throws Exception { if (SystemTestEnvironment.INSTALL_KEYCLOAK) { LOGGER.info("Installing Keycloak : {}", OPERATOR_NS); + KubernetesClient client = kubeClient.client(); - kubeClient.client().namespaces().createOrReplace(new NamespaceBuilder().withNewMetadata().withName(OPERATOR_NS).endMetadata().build()); + return CompletableFuture.runAsync(() -> { + createNamespace(kubeClient); + createKeycloakOperator(client); + awaitPodReady("Keycloak Operator", "app.kubernetes.io/name", "keycloak-operator"); + createOrReplaceAll(client, "keycloak-postgres.yml"); + awaitPodReady("Keycloak Postgres DB", "app", "postgresql-db"); + createSecrets(client); + createOrReplaceAll(client, "keycloak-instance.yml"); + awaitPodReady("Keycloak Application", "app", KC_NAME); + createOrReplaceAll(client, "keycloak-realm.yml"); + TestUtils.waitFor("Keycloak realm import", 1_000, 600_000, KeycloakOperatorManager::realmImportSucceeded); + AtomicInteger countdown = new AtomicInteger(5); + TestUtils.waitFor("Keycloak Pod rolling buffer", 1_000, 20_000, () -> countdown.getAndDecrement() < 1); + awaitPodReady("Keycloak Application", "app", KC_NAME); + LOGGER.info("Keycloak instance is ready"); + }); + } else { + LOGGER.info("Keycloak is not installed suite will use values from env vars for oauth"); + return CompletableFuture.completedFuture(null); + } + } + + static void createNamespace(KubeClient kubeClient) { + if (Boolean.TRUE.equals(kubeClient.client().namespaces().withName(OPERATOR_NS).delete())) { + TestUtils.waitFor("Existing keycloak namespace to be removed", + 1_000, 600_000, + () -> !kubeClient.namespaceExists(OPERATOR_NS)); + } + + Namespace ns = kubeClient.client().namespaces() + .createOrReplace(new NamespaceBuilder() + .withNewMetadata() + .withName(OPERATOR_NS) + .endMetadata() + .build()); + INSTALLED_RESOURCES.add(ns); + } - SecurityUtils.TlsConfig tls = SecurityUtils.getTLSConfig(OPERATOR_NS + ".svc"); + static void createSecrets(KubernetesClient client) { + SecurityUtils.TlsConfig tls; - Secret keycloakCert = new SecretBuilder() + try { + tls = SecurityUtils.getTLSConfig(OPERATOR_NS + ".svc"); + } catch (Exception e) { + throw new RuntimeException(e); + } + + Stream.of( + new SecretBuilder() .withNewMetadata() - .withName("sso-x509-https-secret") - .withNamespace(OPERATOR_NS) + .withName(KeycloakInstance.KEYCLOAK_SECRET_NAME) + .withNamespace(OPERATOR_NS) .endMetadata() .withType("kubernetes.io/tls") .withData(Map.of( - "tls.crt", new String(Base64.getEncoder().encode(tls.getCert().getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8), - "tls.key", new String(Base64.getEncoder().encode(tls.getKey().getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8)) - ) - .build(); - kubeClient.client().secrets().inNamespace(OPERATOR_NS).createOrReplace(keycloakCert); - - List keycloakInstallFiles = Arrays.asList( - "https://github.com/keycloak/keycloak-operator/raw/" + SystemTestEnvironment.KEYCLOAK_VERSION + "/deploy/service_account.yaml", - "https://github.com/keycloak/keycloak-operator/raw/" + SystemTestEnvironment.KEYCLOAK_VERSION + "/deploy/role_binding.yaml", - "https://github.com/keycloak/keycloak-operator/raw/" + SystemTestEnvironment.KEYCLOAK_VERSION + "/deploy/role.yaml", - "https://raw.githubusercontent.com/keycloak/keycloak-operator/" + SystemTestEnvironment.KEYCLOAK_VERSION + "/deploy/cluster_roles/cluster_role_binding.yaml", - "https://github.com/keycloak/keycloak-operator/raw/" + SystemTestEnvironment.KEYCLOAK_VERSION + "/deploy/cluster_roles/cluster_role.yaml", - "https://github.com/keycloak/keycloak-operator/raw/" + SystemTestEnvironment.KEYCLOAK_VERSION + "/deploy/crds/keycloak.org_keycloakbackups_crd.yaml", - "https://github.com/keycloak/keycloak-operator/raw/" + SystemTestEnvironment.KEYCLOAK_VERSION + "/deploy/crds/keycloak.org_keycloakclients_crd.yaml", - "https://github.com/keycloak/keycloak-operator/raw/" + SystemTestEnvironment.KEYCLOAK_VERSION + "/deploy/crds/keycloak.org_keycloakrealms_crd.yaml", - "https://github.com/keycloak/keycloak-operator/raw/" + SystemTestEnvironment.KEYCLOAK_VERSION + "/deploy/crds/keycloak.org_keycloaks_crd.yaml", - "https://github.com/keycloak/keycloak-operator/raw/" + SystemTestEnvironment.KEYCLOAK_VERSION + "/deploy/crds/keycloak.org_keycloakusers_crd.yaml", - "https://github.com/keycloak/keycloak-operator/raw/" + SystemTestEnvironment.KEYCLOAK_VERSION + "/deploy/operator.yaml" - ); - - for (String urlString : keycloakInstallFiles) { - URL url = new URL(urlString); - INSTALLED_RESOURCES.add(kubeClient.client().load(url.openStream()).get().get(0)); - } - - for (HasMetadata resource : INSTALLED_RESOURCES) { - resource.getMetadata().setNamespace(OPERATOR_NS); - kubeClient.client().resource(resource).inNamespace(OPERATOR_NS).createOrReplace(); - } - - kubeClient.cmdClient().namespace(OPERATOR_NS) - .execInCurrentNamespace("apply", "-f", - Paths.get(Environment.SUITE_ROOT, "src", "main", "resources", "keycloak.yml").toAbsolutePath().toString()); - - LOGGER.info("Done installing Keycloak : {}", OPERATOR_NS); - return TestUtils.asyncWaitFor("Keycloak instance ready", 1_000, 600_000, () -> - TestUtils.isPodReady(KubeClient.getInstance().client().pods().inNamespace(OPERATOR_NS) - .list().getItems().stream().filter(pod -> - pod.getMetadata().getName().contains("keycloak-0")).findFirst().orElse(null))) - .thenRun(() -> LOGGER.info("Keycloak instance is ready")); - } else { - LOGGER.info("Keycloak is not installed suite will use values from env vars for oauth"); - return CompletableFuture.completedFuture(null); + "tls.crt", base64Encode(tls.getCert()), + "tls.key", base64Encode(tls.getKey()))), + new SecretBuilder() + .withNewMetadata() + .withName("keycloak-db-secret") + .withNamespace(OPERATOR_NS) + .endMetadata() + .withData(Map.of( + "username", base64Encode("postgres"), + "password", base64Encode("postgrespass")))) + .map(SecretBuilder::build) + .map(client.secrets().inNamespace(OPERATOR_NS)::createOrReplace) + .forEach(INSTALLED_RESOURCES::add); + } + + static String base64Encode(String value) { + return new String(Base64.getEncoder().encode(value.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8); + } + + static void createKeycloakOperator(KubernetesClient client) { + Stream.of( + "keycloaks.k8s.keycloak.org-v1.yml", + "keycloakrealmimports.k8s.keycloak.org-v1.yml", + "kubernetes.yml") + .map(KEYCLOAK_RESOURCE_BASEURL::concat) + .map(t -> { + try { + return new URL(t).openStream(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }) + .map(client::load) + .map(Gettable::get) + .flatMap(Collection::stream) + .forEach(resource -> createOrReplace(client, resource)); + } + + static void createOrReplaceAll(KubernetesClient client, String resourceName) { + try (InputStream stream = KeycloakOperatorManager.class.getClassLoader().getResourceAsStream(resourceName)) { + client.load(stream).get().stream().forEach(resource -> createOrReplace(client, resource)); + } catch (IOException e) { + throw new UncheckedIOException(e); } } + static void createOrReplace(KubernetesClient client, HasMetadata resource) { + resource.getMetadata().setNamespace(OPERATOR_NS); + client.resource(resource).inNamespace(OPERATOR_NS).createOrReplace(); + INSTALLED_RESOURCES.add(resource); + } + + static void awaitPodReady(String description, String labelName, String labelValue) { + TestUtils.waitFor(description + " ready", 1_000, 600_000, () -> isPodReady(labelName, labelValue)); + } + + static boolean isPodReady(String labelName, String labelValue) { + return TestUtils.isPodReady(KubeClient.getInstance() + .client() + .pods() + .inNamespace(OPERATOR_NS) + .withLabel(labelName, labelValue) + .list() + .getItems() + .stream() + .findFirst() + .orElse(null)); + } + + static boolean realmImportSucceeded() { + return Optional.ofNullable(KubeClient.getInstance() + .client() + .batch() + .v1() + .jobs() + .inNamespace(OPERATOR_NS) + .withName("demo-realm") + .get()) + .map(job -> Optional.of(job) + .map(Job::getStatus) + .map(JobStatus::getConditions) + .orElseGet(Collections::emptyList) + .stream() + .anyMatch(c -> "Complete".equals(c.getType()) && "True".equals(c.getStatus())) ? job : null) + .filter(Objects::nonNull) + .map(job -> job.getStatus().getSucceeded()) + .filter(Objects::nonNull) + .map(succeeded -> succeeded > 0) + .orElse(Boolean.FALSE); + } + public static CompletableFuture uninstallKeycloak(KubeClient kubeClient) { if (SystemTestEnvironment.INSTALL_KEYCLOAK && kubeClient.namespaceExists(OPERATOR_NS) && !SystemTestEnvironment.SKIP_TEARDOWN) { LOGGER.info("Deleting Keycloak : {}", OPERATOR_NS); - kubeClient.cmdClient().namespace(OPERATOR_NS).execInCurrentNamespace("delete", "-f", - Paths.get(Environment.SUITE_ROOT, "src", "main", "resources", "keycloak.yml").toAbsolutePath().toString()); - kubeClient.cmdClient().namespace(OPERATOR_NS) - .execInCurrentNamespace("delete", "keycloak", "--all"); - INSTALLED_RESOURCES.forEach(resource -> kubeClient.client().resource(resource).inNamespace(OPERATOR_NS).delete()); - kubeClient.client().namespaces().withName(OPERATOR_NS).delete(); + KubernetesClient client = kubeClient.client(); + + INSTALLED_RESOURCES.forEach(resource -> client.resource(resource).inNamespace(OPERATOR_NS).delete()); + return TestUtils.asyncWaitFor("Delete Keycloak", 2_000, FleetShardOperatorManager.DELETE_TIMEOUT_MS, () -> - kubeClient.client().pods().inNamespace(OPERATOR_NS).list().getItems().stream().noneMatch(pod -> + client.pods().inNamespace(OPERATOR_NS).list().getItems().stream().noneMatch(pod -> pod.getMetadata().getName().contains("keycloak-0")) && !kubeClient.namespaceExists(OPERATOR_NS)); } else { diff --git a/systemtest/src/main/resources/keycloak-instance.yml b/systemtest/src/main/resources/keycloak-instance.yml new file mode 100644 index 000000000..ac6551db8 --- /dev/null +++ b/systemtest/src/main/resources/keycloak-instance.yml @@ -0,0 +1,26 @@ +--- +apiVersion: k8s.keycloak.org/v2alpha1 +kind: Keycloak +metadata: + name: keycloak +spec: + instances: 1 + db: + vendor: postgres + host: postgresql-db + usernameSecret: + name: keycloak-db-secret + key: username + passwordSecret: + name: keycloak-db-secret + key: password + http: + httpEnabled: false + tlsSecret: sso-x509-https-secret + hostname: + hostname: keycloak + ingress: + enabled: false + additionalOptions: + - name: http-relative-path + value: '/auth' diff --git a/systemtest/src/main/resources/keycloak-postgres.yml b/systemtest/src/main/resources/keycloak-postgres.yml new file mode 100644 index 000000000..13767381c --- /dev/null +++ b/systemtest/src/main/resources/keycloak-postgres.yml @@ -0,0 +1,54 @@ +--- +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: keycloak-postgres +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi +--- +kind: StatefulSet +apiVersion: apps/v1 +metadata: + name: keycloak-postgres +spec: + serviceName: postgresql-db-service + selector: + matchLabels: + app: postgresql-db + replicas: 1 + template: + metadata: + labels: + app: postgresql-db + spec: + volumes: + - name: keycloak-postgres + persistentVolumeClaim: + claimName: keycloak-postgres + containers: + - name: postgresql-db + image: postgres:15 + env: + - name: POSTGRES_PASSWORD + value: postgrespass + - name: POSTGRES_DB + value: keycloak + volumeMounts: + - name: keycloak-postgres + mountPath: /var/lib/postgresql +--- +kind: Service +apiVersion: v1 +metadata: + name: postgresql-db +spec: + selector: + app: postgresql-db + type: ClusterIP + ports: + - port: 5432 + targetPort: 5432 diff --git a/systemtest/src/main/resources/keycloak-realm.yml b/systemtest/src/main/resources/keycloak-realm.yml new file mode 100644 index 000000000..650aae792 --- /dev/null +++ b/systemtest/src/main/resources/keycloak-realm.yml @@ -0,0 +1,22 @@ +--- +apiVersion: k8s.keycloak.org/v2alpha1 +kind: KeycloakRealmImport +metadata: + name: demo-realm +spec: + keycloakCRName: keycloak + realm: + id: demo + realm: demo + displayName: demo + description: 'kas-fleetshard-systemtests: demo' + enabled: true + clients: + - clientId: kafka + description: "kas-fleetshard-systemtests: kafka client" + secret: kafka + name: kafka + serviceAccountsEnabled: true + protocol: openid-connect + publicClient: false + clientAuthenticatorType: client-secret diff --git a/systemtest/src/main/resources/keycloak.yml b/systemtest/src/main/resources/keycloak.yml deleted file mode 100644 index f7cf5b12b..000000000 --- a/systemtest/src/main/resources/keycloak.yml +++ /dev/null @@ -1,49 +0,0 @@ -apiVersion: keycloak.org/v1alpha1 -kind: Keycloak -metadata: - name: example-keycloak - labels: - app: sso -spec: - instances: 1 - extensions: - - https://github.com/aerogear/keycloak-metrics-spi/releases/download/1.0.4/keycloak-metrics-spi-1.0.4.jar - externalAccess: - enabled: False - podDisruptionBudget: - enabled: True ---- -apiVersion: keycloak.org/v1alpha1 -kind: KeycloakRealm -metadata: - name: demo - labels: - app: demo -spec: - realm: - id: "demo" - realm: "demo" - enabled: True - displayName: "demo" - instanceSelector: - matchLabels: - app: sso ---- -apiVersion: keycloak.org/v1alpha1 -kind: KeycloakClient -metadata: - name: kafka - labels: - app: sso -spec: - realmSelector: - matchLabels: - app: demo - client: - clientId: kafka - secret: kafka - clientAuthenticatorType: client-secret - protocol: openid-connect - serviceAccountsEnabled: true - standardFlowEnabled: false - implicitFlowEnabled: false \ No newline at end of file diff --git a/systemtest/src/main/resources/log4j2.properties b/systemtest/src/main/resources/log4j2.properties index 944c0b561..2bd0fa1d3 100644 --- a/systemtest/src/main/resources/log4j2.properties +++ b/systemtest/src/main/resources/log4j2.properties @@ -4,6 +4,7 @@ appender.console.type = Console appender.console.name = STDOUT appender.console.layout.type = PatternLayout appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss}{GMT} %highlight{%-5p} [%t] [%c{1}:%L] %m%n +appender.console.follow = true appender.rolling.type = RollingFile appender.rolling.name = RollingFile diff --git a/systemtest/src/test/java/org/bf2/systemtest/unit/SuiteUnitTest.java b/systemtest/src/test/java/org/bf2/systemtest/unit/SuiteUnitTest.java index ad882f0f7..a9e5bc89a 100644 --- a/systemtest/src/test/java/org/bf2/systemtest/unit/SuiteUnitTest.java +++ b/systemtest/src/test/java/org/bf2/systemtest/unit/SuiteUnitTest.java @@ -94,12 +94,12 @@ void setupMockServer() throws Exception { mockServer.getClient().secrets().inNamespace("keycloak").createOrReplace( new SecretBuilder() .withNewMetadata() - .withName("credential-example-keycloak") + .withName(KeycloakInstance.ADMIN_SECRET) .endMetadata() .withData( Map.of( - "ADMIN_USERNAME", "YWRtaW4=", - "ADMIN_PASSWORD", "YWRtaW4=")) + "username", "YWRtaW4=", + "password", "YWRtaW4=")) .build()); } @@ -140,7 +140,7 @@ void testExecutorError() { @ParallelTest void testKeycloakInstance() { KeycloakInstance k = new KeycloakInstance("keycloak"); - assertEquals("https://keycloak.keycloak.svc:8443/auth/realms/demo/protocol/openid-connect/certs", k.getJwksEndpointUri()); + assertEquals("https://keycloak-service.keycloak.svc:8443/auth/realms/demo/protocol/openid-connect/certs", k.getJwksEndpointUri()); assertEquals("admin", k.getUsername()); assertEquals("admin", k.getPassword()); assertNotNull(k.getKeycloakCert());