Java client with TLS

We have a temporal server installed in openshift cluster behind https HAproxy. In order to access it we need to establish tls connection (temporal server itself is not ssl enabled).
We are able to do this using tctl:

tctl --ad=host:443 --tls_ca_path=/tmp/ca.pem cluster health
temporal.api.workflowservice.v1.WorkflowService: SERVING

But how to do that using java client? I tried to do smth similar like:

sslContext = //...//
serviceStubsOptions = WorkflowServiceStubsOptions.newBuilder()
            .setSslContext( sslContext)
            .setUseInsecureTrustManager(true)
            .build()
        )
        .setTarget(temporalServerAddress)
        .build();

But that fails with error:

io.grpc.StatusRuntimeException: UNAVAILABLE: Failed ALPN negotiation: Unable to find compatible >protocol
Channel Pipeline: [SslHandler#0, ProtocolNegotiators$ClientTlsHandler#0, >WriteBufferingAndExceptionHandler#0, DefaultChannelPipeline$TailContext#0]

Can you show how you create context and which ssl context builder you use?
Also being able to see the whole exception would help imo.

Here is sample that uses SimpleSslContextBuilder, do you get the same exception with that?

I tried couple of ways to create ssl context:

sslContext = SslContextBuilder.forClient()
        .trustManager(Files.newInputStream(Paths.get("ca.pem")))
        .applicationProtocolConfig(
          new ApplicationProtocolConfig(
            ApplicationProtocolConfig.Protocol.ALPN,
            ApplicationProtocolConfig.SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL,
            ApplicationProtocolConfig.SelectedListenerFailureBehavior
              .CHOOSE_MY_LAST_PROTOCOL, "h2"))
        .clientAuth(ClientAuth.NONE).build();

and insecure:

sslContext = SimpleSslContextBuilder
        .noKeyOrCertChain()
        .setUseInsecureTrustManager(true)
        .build();

Both fail with the same exception:

Exception in thread “main” io.grpc.StatusRuntimeException: UNAVAILABLE: Failed ALPN negotiation: Unable to find compatible protocol
Channel Pipeline: [SslHandler#0, ProtocolNegotiators$ClientTlsHandler#0, WriteBufferingAndExceptionHandler#0, DefaultChannelPipeline$TailContext#0]
at io.grpc.stub.ClientCalls.toStatusRuntimeException(ClientCalls.java:271)
at io.grpc.stub.ClientCalls.getUnchecked(ClientCalls.java:252)
at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:165)
at io.grpc.health.v1.HealthGrpc$HealthBlockingStub.check(HealthGrpc.java:252)
at io.temporal.serviceclient.ChannelManager.healthCheck(ChannelManager.java:302)
at io.temporal.serviceclient.ChannelManager.lambda$connect$2(ChannelManager.java:277)
at io.temporal.internal.retryer.GrpcSyncRetryer.retry(GrpcSyncRetryer.java:60)
at io.temporal.internal.retryer.GrpcRetryer.retryWithResult(GrpcRetryer.java:66)
at io.temporal.internal.retryer.GrpcRetryer.retryWithResult(GrpcRetryer.java:60)
at io.temporal.serviceclient.ChannelManager.connect(ChannelManager.java:277)
at io.temporal.serviceclient.WorkflowServiceStubsImpl.connect(WorkflowServiceStubsImpl.java:159)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at io.temporal.internal.WorkflowThreadMarker.lambda$protectFromWorkflowThread$1(WorkflowThreadMarker.java:83)
at com.sun.proxy.$Proxy66.connect(Unknown Source)
at io.temporal.worker.WorkerFactory.start(WorkerFactory.java:207)
at com.te.bnking.st.poc.App.startWorker(App.java:120)
at com.te.bnking.stpoc.App.main(App.java:43)

Thanks,
For the secure connection, could you make sure that your proxy is configured for HTTP/2 via alpn?

Seems maybe some proxy config issue? Saw this thread in grpc-java repo that might be helpful.

No, I cannot. I don’t have any access to the proxy.
And it shouldn’t be an issue here since tctl works fine, right?

And it shouldn’t be an issue here since tctl works fine, right?

tctl is written in Go and uses different libraries for gRPC, for java we rely on grpc-java (and transitively grpc-netty-shaded). SDK also provides SimpleSslContextBuilder out of box that works in most cases.

I believe it’s worth trying to ask this on their repo and see if anyone has run into same issue, as I am not sure this is problem with temporal java sdk itself and don’t have access to your particular proxy to be able to reproduce.

No, I cannot. I don’t have any access to the proxy.

We don’t typically debug user environments, but especially if they don’t have an access to them. You have a problem with a basic gRPC connectivity here, it’s not Temporal related. Pretty much no meaningful Temporal code involved up to the point of this error.

SslContextBuilder.forClient()
.trustManager(Files.newInputStream(Paths.get(“ca.pem”)))
.applicationProtocolConfig(
new ApplicationProtocolConfig(
ApplicationProtocolConfig.Protocol.ALPN,
ApplicationProtocolConfig.SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL,
ApplicationProtocolConfig.SelectedListenerFailureBehavior
.CHOOSE_MY_LAST_PROTOCOL, “h2”))
.clientAuth(ClientAuth.NONE).build();

Please don’t set applicationProtocolConfig directly. Instead, use GrpcSslContexts.configure(). This is what SimpleSslContextBuilder does inside.