Keycloak custom Vault SPI (with Hashicorp Vault)

Dear All,

I am trying to override the VaultProvider and VaultProviderFactory extension classes to use Hashicorp Vault.
I have tried to integrate these providers with the following Hashicorp Vault libraries, which provide methods for communicating with Hashicorp Vault as documented in the official Hashicorp Vault page (HTTP API: Libraries | Vault | HashiCorp Developer):

  1. quarkiverse/quarkus-vault: Quarkus HashiCorp Vault extension
  2. BetterCloud/vault-java-driver: Zero-dependency Java client for HashiCorp’s Vault

However when deploying the custom Vault SPI I am getting the following error (when using a fat Uber jar):

ERROR: Failed to run ‘build’ command.
Error details:
java.lang.NullPointerException
at java.base/java.util.Objects.requireNonNull(Objects.java:233)
at java.base/java.util.ImmutableCollections$List12.(ImmutableCollections.java:563)
at java.base/java.util.List.of(List.java:937)
at io.quarkus.paths.OpenContainerPathTree.getRoots(OpenContainerPathTree.java:96)
at io.quarkus.paths.SharedArchivePathTree$CallerOpenPathTree.getRoots(SharedArchivePathTree.java:142)
at io.quarkus.bootstrap.classloading.PathTreeClassPathElement.toString(PathTreeClassPathElement.java:214)
at java.base/java.util.Formatter$FormatSpecifier.printString(Formatter.java:3158)
at java.base/java.util.Formatter$FormatSpecifier.print(Formatter.java:3036)
at java.base/java.util.Formatter.format(Formatter.java:2791)
at java.base/java.util.Formatter.format(Formatter.java:2728)
at java.base/java.lang.String.format(String.java:4386)
at org.jboss.logmanager.ExtFormatter.formatMessagePrintf(ExtFormatter.java:144)
at org.jboss.logmanager.ExtFormatter.formatMessage(ExtFormatter.java:91)
at org.jboss.logmanager.formatters.Formatters$16.renderRaw(Formatters.java:832)
at org.jboss.logmanager.formatters.Formatters$JustifyingFormatStep.render(Formatters.java:227)
at org.jboss.logmanager.formatters.MultistepFormatter.format(MultistepFormatter.java:90)
at org.jboss.logmanager.ExtFormatter.format(ExtFormatter.java:58)
at io.quarkus.bootstrap.logging.QuarkusDelayedHandler.close(QuarkusDelayedHandler.java:157)
at io.quarkus.bootstrap.runner.QuarkusEntryPoint.main(QuarkusEntryPoint.java:35)
at org.keycloak.quarkus.runtime.cli.Picocli.build(Picocli.java:945)
at org.keycloak.quarkus.runtime.cli.command.Build.run(Build.java:91)
at picocli.CommandLine.executeUserObject(CommandLine.java:2030)
at picocli.CommandLine.access$1500(CommandLine.java:148)
at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2465)
at picocli.CommandLine$RunLast.handle(CommandLine.java:2457)
at picocli.CommandLine$RunLast.handle(CommandLine.java:2419)
at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2277)
at picocli.CommandLine$RunLast.execute(CommandLine.java:2421)
at picocli.CommandLine.execute(CommandLine.java:2174)
at org.keycloak.quarkus.runtime.cli.Picocli.runReAugmentation(Picocli.java:317)
at org.keycloak.quarkus.runtime.cli.Picocli.runReAugmentationIfNeeded(Picocli.java:230)
at org.keycloak.quarkus.runtime.cli.Picocli.parseAndRun(Picocli.java:127)
at org.keycloak.quarkus.runtime.KeycloakMain.main(KeycloakMain.java:116)
at org.keycloak.quarkus.runtime.KeycloakMain.main(KeycloakMain.java:71)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at io.quarkus.bootstrap.runner.QuarkusEntryPoint.doRun(QuarkusEntryPoint.java:62)
at io.quarkus.bootstrap.runner.QuarkusEntryPoint.main(QuarkusEntryPoint.java:33)

And the following error with a typical jar:

ERROR: Unexpected error when starting the server in (production) mode
Error details:
java.lang.RuntimeException: Failed to start quarkus
at io.quarkus.runner.ApplicationImpl.(Unknown Source)
at java.base/jdk.internal.misc.Unsafe.ensureClassInitialized0(Native Method)
at java.base/jdk.internal.misc.Unsafe.ensureClassInitialized(Unsafe.java:1160)
at java.base/jdk.internal.reflect.MethodHandleAccessorFactory.ensureClassInitialized(MethodHandleAccessorFactory.java:300)
at java.base/jdk.internal.reflect.MethodHandleAccessorFactory.newConstructorAccessor(MethodHandleAccessorFactory.java:103)
at java.base/jdk.internal.reflect.ReflectionFactory.newConstructorAccessor(ReflectionFactory.java:200)
at java.base/java.lang.reflect.Constructor.acquireConstructorAccessor(Constructor.java:549)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486)
at io.quarkus.runtime.Quarkus.run(Quarkus.java:70)
at org.keycloak.quarkus.runtime.KeycloakMain.start(KeycloakMain.java:145)
at org.keycloak.quarkus.runtime.cli.Picocli.start(Picocli.java:941)
at org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.run(AbstractStartCommand.java:49)
at picocli.CommandLine.executeUserObject(CommandLine.java:2030)
at picocli.CommandLine.access$1500(CommandLine.java:148)
at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2465)
at picocli.CommandLine$RunLast.handle(CommandLine.java:2457)
at picocli.CommandLine$RunLast.handle(CommandLine.java:2419)
at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2277)
at picocli.CommandLine$RunLast.execute(CommandLine.java:2421)
at picocli.CommandLine.execute(CommandLine.java:2174)
at org.keycloak.quarkus.runtime.cli.Picocli.parseAndRun(Picocli.java:130)
at org.keycloak.quarkus.runtime.KeycloakMain.main(KeycloakMain.java:116)
at org.keycloak.quarkus.runtime.KeycloakMain.main(KeycloakMain.java:71)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at io.quarkus.bootstrap.runner.QuarkusEntryPoint.doRun(QuarkusEntryPoint.java:62)
at io.quarkus.bootstrap.runner.QuarkusEntryPoint.main(QuarkusEntryPoint.java:33)
Caused by: java.lang.NoClassDefFoundError: io/quarkus/vault/VaultKVSecretEngine
at org.keycloak.vault.VaultService.readVaultSecrets(VaultService.java:56)
at org.keycloak.vault.VaultService.(VaultService.java:47)
at org.keycloak.vault.HashicorpVaultProviderFactory.init(HashicorpVaultProviderFactory.java:28)
at org.keycloak.quarkus.runtime.integration.QuarkusKeycloakSessionFactory.(QuarkusKeycloakSessionFactory.java:75)
at org.keycloak.quarkus.runtime.KeycloakRecorder.configSessionFactory(KeycloakRecorder.java:125)
at io.quarkus.deployment.steps.KeycloakProcessor$configureKeycloakSessionFactory343981823.deploy_4(Unknown Source)
at io.quarkus.deployment.steps.KeycloakProcessor$configureKeycloakSessionFactory343981823.deploy(Unknown Source)
… 28 more
Caused by: java.lang.ClassNotFoundException: io.quarkus.vault.VaultKVSecretEngine
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
at io.quarkus.bootstrap.runner.RunnerClassLoader.loadClass(RunnerClassLoader.java:114)
at io.quarkus.bootstrap.runner.RunnerClassLoader.loadClass(RunnerClassLoader.java:72)
… 35 more

When using the vault-java-driver library I am getting the ClassNotFound and ClassDefNotFound exception for the VaultConfig and Vault classes which I suppose is the same root cause.

Could you please help me understand how to integrate these vault libraries with keycloak custom SPI implementation?
Are there any conflicts with these libraries and the core keycloak libraries and therefore there is no possible integration with Hashicorp Vault and Keycloak?
How could I fix this please to make it work properly?

Many thanks,

My understanding with Keycloak extensions that depend on Quarkus extensions is that there isn’t a good way to make them work, as the Quarkus extension has to get added before the build phase (in the Keycloak repo). I had problems with this when trying to integrate the Quarkus Keycloak admin client to run inside Keycloak. The only way I was ever able to get it to work was to add it to the Keycloak build.

mbartos has a project to add Quarkus extensions to Keycloak here GitHub - mabartos/keycloak-quarkus-extensions: Easy way how to add Quarkus extensions to your Keycloak deployment but I couldn’t figure out how to use it as part of a normal Docker build process, and wasn’t willing to have something else I didn’t understand (re)build my image.

1 Like

I’m currently developing a custom Vault SPI for OpenBao and HashiCorp Vault, which is planned to be actively maintained for foreseeable future, but it’s not usable yet. You can follow the progress here. However, it won’t help with your question about the Quarkus extension.

1 Like

Hi!

Thanks a lot for the provided project, I will check the implementation details, very cool good luck!

If anyone is interested on how I overcame the issues described above, I used the Hashicorp Vault api services to call the Vault methods from my SPI, without installing any library listed above.

Many thanks,

Thank you xgp for the advice :slight_smile: