<p><strong>Problem</strong></p>

<hr>

<p>I am trying to make a client in Java using <code>gRPC</code>. I have been given access to a <code>kubernetes</code> namespace to test out the client. However, all I have is the certificate authority for the cluster and a bearer token.</p>

<pre><code>apiVersion: v1
clusters:
- cluster:
    certificate-authority: /etc/ssl/certs/devwat-dal13-cruiser15-ca-bundle.pem
    server: https://&lt;host-ip&gt;:&lt;port&gt;
  name: devwat-dal13-cruiser15
contexts:
- context:
    cluster: devwat-dal13-cruiser15
    namespace: interns
    user: devwat-dal13-cruiser15-sa-interns-editor
  name: devwat-dal13-cruiser15-interns
current-context: devwat-dal13-cruiser15-interns
kind: Config
preferences: {}
users:
- name: devwat-dal13-cruiser15-sa-interns-editor
  user:
    token: &lt;token&gt;
</code></pre>

<p><strong>Code</strong></p>

<hr>

<p>I don't know much about <code>SSL</code> and certificates but I tried to follow the documentation online on using <code>SSL/TLS</code> with <code>gRPC</code> with Java and came up with the following:</p>

<pre><code>public class TrainerClient {
    private ManagedChannel channel;
    private TrainerGrpc.TrainerBlockingStub stub;

    //private final String OVERRIDE_AUTHORITY = "24164dfe5c7842c98de431e53b6111d9-kubernetes-ca";
    private final String CERT_FILE_PATH = Paths.get("/etc", "ssl", "certs", "devwat-dal13-cruiser15-ca-bundle.pem").toString();

    private static final Logger logger = Logger.getLogger(TrainerClient.class.getName());

    public TrainerClient(URL serviceUrl) {


        File certFile = new File(CERT_FILE_PATH);

        try {
            logger.info("Initializing channel using SSL...");
            this.channel = NettyChannelBuilder.forAddress(serviceUrl.getHost(), serviceUrl.getPort())
                    //.overrideAuthority(OVERRIDE_AUTHORITY)
                    .sslContext(getSslContext(certFile))
                    .build();

            logger.info("Initializing new blocking stub...");
            this.stub = TrainerGrpc.newBlockingStub(channel);
        } catch (Exception ex) {
            logger.log(Level.SEVERE, "Channel build failed: {0}", ex.toString());
            System.exit(1);
        }
    }

    public static void main(String[] args) {

        TrainerClient client = null;
        URL url = null;
        String fullUrl = "http://localhost:8443";

        try {
            logger.info("Forming URL...");
            url = new URL(fullUrl);

            logger.info("Initializing client...");
            client = new TrainerClient(url);

            // Client Function Calls
            TrainerOuterClass.GetAllRequest request = TrainerOuterClass.GetAllRequest.newBuilder().setUserId("").build();
            TrainerOuterClass.GetAllResponse response = client.getAllTrainingsJobs(request);


        } catch (Exception ex) {
            if (ex instanceof MalformedURLException) {
                logger.log(Level.SEVERE, "URL is malformed.");
            } else {
                logger.log(Level.SEVERE, "Exception has occurred: {0}", ex.getStackTrace());
                ex.printStackTrace();
            }
        } finally {
            if (client != null) {
                try {
                    logger.info("Shutting down client...");
                    client.shutdown();
                } catch (InterruptedException ex) {
                    logger.log(Level.WARNING, "Channel shutdown was interrupted.");
                }
            }
        }
    }

    public SslContext getSslContext(File certFile) throws SSLException {
        return GrpcSslContexts.forClient()
                .trustManager(certFile)
                .build();
    }

    private void shutdown() throws InterruptedException {
        channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
    }
}
</code></pre>

<p>The pod type is <code>ClusterIP</code> and is being port-forwarded to <code>localhost</code> with port <code>8443</code>.</p>

<p><strong>Error</strong></p>

<hr>

<p>When I run this, I get the following stack trace:</p>

<pre><code>SEVERE: Exception has occurred: 

io.grpc.stub.ClientCalls.toStatusRuntimeException(ClientCalls.java:210)
io.grpc.StatusRuntimeException: UNAVAILABLE
    at io.grpc.stub.ClientCalls.toStatusRuntimeException(ClientCalls.java:210)
    at io.grpc.stub.ClientCalls.getUnchecked(ClientCalls.java:191)
    at io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:124)
    at grpc.trainer.v2.TrainerGrpc$TrainerBlockingStub.getAllTrainingsJobs(TrainerGrpc.java:695)
    at me.mikeygulati.grpc.TrainerClient.getAllTrainingsJobs(TrainerClient.java:70)
    at me.mikeygulati.grpc.TrainerClient.main(TrainerClient.java:138)
Caused by: javax.net.ssl.SSLHandshakeException: General OpenSslEngine problem
    at io.netty.handler.ssl.ReferenceCountedOpenSslContext$AbstractCertificateVerifier.verify(ReferenceCountedOpenSslContext.java:648)
    at io.netty.internal.tcnative.SSL.readFromSSL(Native Method)
    at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.readPlaintextData(ReferenceCountedOpenSslEngine.java:482)
    at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.unwrap(ReferenceCountedOpenSslEngine.java:1020)
    at io.netty.handler.ssl.ReferenceCountedOpenSslEngine.unwrap(ReferenceCountedOpenSslEngine.java:1127)
    at io.netty.handler.ssl.SslHandler$SslEngineType$1.unwrap(SslHandler.java:210)
    at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1215)
    at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1127)
    at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1162)
    at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:489)
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:428)
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340)
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1359)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362)
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348)
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:935)
    at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:134)
    at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:645)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580)
    at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459)
    at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858)
    at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:138)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.security.cert.CertificateException: No name matching localhost found
    at sun.security.util.HostnameChecker.matchDNS(HostnameChecker.java:231)
    at sun.security.util.HostnameChecker.match(HostnameChecker.java:96)
    at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:455)
    at sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:436)
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:252)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:136)
    at io.netty.handler.ssl.ReferenceCountedOpenSslClientContext$ExtendedTrustManagerVerifyCallback.verify(ReferenceCountedOpenSslClientContext.java:221)
    at io.netty.handler.ssl.ReferenceCountedOpenSslContext$AbstractCertificateVerifier.verify(ReferenceCountedOpenSslContext.java:644)
    ... 26 more
Jul 24, 2018 10:52:05 AM me.mikeygulati.grpc.TrainerClient main
</code></pre>

<p>From what I have read online, this happens because the <code>Common Name</code> on the <code>CA</code> does not match the hostname, in my case, <code>localhost</code>. I have tried using an <code>Override Authority</code> so that it would match the <code>Common Name</code> in the <code>CA</code> but I got the same error.</p>

<p>So, I am fairly sure this is not the correct way to do it. I feel like I should have been supplied a client certificate and a client key with the <code>kubernetes</code> cluster but I didn't so, I want to ask if maybe there's something wrong with what I am doing.</p>

<p>Figured it out.</p>

<p>My company had a client certificate (<code>client.crt</code>) lying around that I was supposed to use instead of the <code>CA</code>. When I used that certificate instead with the proper override authority, the error went away.</p>
