Skip to content

Commit 1156db4

Browse files
authored
Fix Java & Go SDK TLS support (#986)
* Go SDK: Rename NewAuthGrpcClient() to NewSecureGrpcClient() to take into account TLS in naming. * Java SDK: Update FeastClient to support TLS transport security. * Java SDK: Update createSecure() to accept security params via SecurityConfig. * Fix issue where go sdk did not use system certificate if cert path was not specified in SecurityConfig * Go SDK: Replace unneeded else if check with else instead. * Java SDK: Update FeastClient.createSecure() to throw IllegalArgumentException instead of SSLException. * Fix java lint
1 parent ff43765 commit 1156db4

3 files changed

Lines changed: 110 additions & 14 deletions

File tree

sdk/go/client.go

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package feast
22

33
import (
44
"context"
5+
"crypto/x509"
56
"fmt"
67
"github.com/feast-dev/feast/sdk/go/protos/feast/serving"
78
"github.com/opentracing/opentracing-go"
@@ -27,7 +28,7 @@ type GrpcClient struct {
2728
type SecurityConfig struct {
2829
// Whether to enable TLS SSL trasnport security if true.
2930
EnableTLS bool
30-
// Optional: Provides path to TLS certificate use the verify Service identity.
31+
// Optional: Provides path to TLS certificate used the verify Service identity.
3132
TLSCertPath string
3233
// Optional: Credential used for authentication.
3334
// Disables authentication if unspecified.
@@ -36,33 +37,42 @@ type SecurityConfig struct {
3637

3738
// NewGrpcClient constructs a client that can interact via grpc with the feast serving instance at the given host:port.
3839
func NewGrpcClient(host string, port int) (*GrpcClient, error) {
39-
return NewAuthGrpcClient(host, port, SecurityConfig{
40+
return NewSecureGrpcClient(host, port, SecurityConfig{
4041
EnableTLS: false,
4142
Credential: nil,
4243
})
4344
}
4445

45-
// NewAuthGrpcClient constructs a client that can connect with feast serving instances with authentication enabled.
46+
// NewAuthGrpcClient constructs a secure client that uses security features (ie authentication).
4647
// host - hostname of the serving host/instance to connect to.
4748
// port - post of the host to service host/instancf to connect to.
4849
// securityConfig - security config configures client security.
49-
func NewAuthGrpcClient(host string, port int, security SecurityConfig) (*GrpcClient, error) {
50+
func NewSecureGrpcClient(host string, port int, security SecurityConfig) (*GrpcClient, error) {
5051
feastCli := &GrpcClient{}
5152
adr := fmt.Sprintf("%s:%d", host, port)
5253

5354
// Compile grpc dial options from security config.
5455
options := []grpc.DialOption{grpc.WithStatsHandler(&ocgrpc.ClientHandler{})}
56+
// Configure client TLS.
5557
if !security.EnableTLS {
5658
options = append(options, grpc.WithInsecure())
57-
}
58-
// Read TLS certificate from given path instead of using system certs if specified.
59-
if security.EnableTLS && security.TLSCertPath != "" {
59+
} else if security.EnableTLS && security.TLSCertPath != "" {
60+
// Read TLS certificate from given path.
6061
tlsCreds, err := credentials.NewClientTLSFromFile(security.TLSCertPath, "")
6162
if err != nil {
6263
return nil, err
6364
}
6465
options = append(options, grpc.WithTransportCredentials(tlsCreds))
66+
} else {
67+
// Use system TLS certificate pool.
68+
certPool, err := x509.SystemCertPool()
69+
if err != nil {
70+
return nil, err
71+
}
72+
tlsCreds := credentials.NewClientTLSFromCert(certPool, "")
73+
options = append(options, grpc.WithTransportCredentials(tlsCreds))
6574
}
75+
6676
// Enable authentication by attaching credentials if given
6777
if security.Credential != nil {
6878
options = append(options, grpc.WithPerRPCCredentials(security.Credential))

sdk/java/src/main/java/com/gojek/feast/FeastClient.java

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,15 @@
2727
import io.grpc.CallCredentials;
2828
import io.grpc.ManagedChannel;
2929
import io.grpc.ManagedChannelBuilder;
30+
import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts;
31+
import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder;
32+
import java.io.File;
3033
import java.util.HashSet;
3134
import java.util.List;
3235
import java.util.Optional;
3336
import java.util.concurrent.TimeUnit;
3437
import java.util.stream.Collectors;
38+
import javax.net.ssl.SSLException;
3539
import org.slf4j.Logger;
3640
import org.slf4j.LoggerFactory;
3741

@@ -52,8 +56,8 @@ public class FeastClient implements AutoCloseable {
5256
* @return {@link FeastClient}
5357
*/
5458
public static FeastClient create(String host, int port) {
55-
ManagedChannel channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext().build();
56-
return new FeastClient(channel, Optional.empty());
59+
// configure client with no security config.
60+
return FeastClient.createSecure(host, port, SecurityConfig.newBuilder().build());
5761
}
5862

5963
/**
@@ -62,13 +66,37 @@ public static FeastClient create(String host, int port) {
6266
*
6367
* @param host hostname or ip address of Feast serving GRPC server
6468
* @param port port number of Feast serving GRPC server
65-
* @param credentials Call credentials used to provide credentials when calling Feast.
69+
* @param securityConfig security options to configure the Feast client. See {@link
70+
* SecurityConfig} for options.
6671
* @return {@link FeastClient}
6772
*/
68-
public static FeastClient createAuthenticated(
69-
String host, int port, CallCredentials credentials) {
70-
ManagedChannel channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext().build();
71-
return new FeastClient(channel, Optional.of(credentials));
73+
public static FeastClient createSecure(String host, int port, SecurityConfig securityConfig) {
74+
// Configure client TLS
75+
ManagedChannel channel = null;
76+
if (securityConfig.isTLSEnabled()) {
77+
if (securityConfig.getCertificatePath().isPresent()) {
78+
String certificatePath = securityConfig.getCertificatePath().get();
79+
// Use custom certificate for TLS
80+
File certificateFile = new File(certificatePath);
81+
try {
82+
channel =
83+
NettyChannelBuilder.forAddress(host, port)
84+
.useTransportSecurity()
85+
.sslContext(GrpcSslContexts.forClient().trustManager(certificateFile).build())
86+
.build();
87+
} catch (SSLException e) {
88+
throw new IllegalArgumentException(
89+
String.format("Invalid Certificate provided at path: %s", certificatePath), e);
90+
}
91+
} else {
92+
// Use system certificates for TLS
93+
channel = ManagedChannelBuilder.forAddress(host, port).useTransportSecurity().build();
94+
}
95+
} else {
96+
// Disable TLS
97+
channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext().build();
98+
}
99+
return new FeastClient(channel, securityConfig.getCredentials());
72100
}
73101

74102
/**
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright 2018-2019 The Feast Authors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* https://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package com.gojek.feast;
18+
19+
import com.google.auto.value.AutoValue;
20+
import io.grpc.CallCredentials;
21+
import java.util.Optional;
22+
23+
/** SecurityConfig captures the security related configuration for FeastClient */
24+
@AutoValue
25+
public abstract class SecurityConfig {
26+
/**
27+
* Enables authentication If specified, the call credentials used to provide credentials to
28+
* authenticate with Feast.
29+
*/
30+
public abstract Optional<CallCredentials> getCredentials();
31+
32+
/** Whether to use TLS transport security is use when connecting to Feast. */
33+
public abstract boolean isTLSEnabled();
34+
35+
/**
36+
* If specified and TLS is enabled, provides path to TLS certificate use the verify Service
37+
* identity.
38+
*/
39+
public abstract Optional<String> getCertificatePath();
40+
41+
@AutoValue.Builder
42+
public abstract static class Builder {
43+
public abstract Builder setCredentials(Optional<CallCredentials> credentials);
44+
45+
public abstract Builder setTLSEnabled(boolean isTLSEnabled);
46+
47+
public abstract Builder setCertificatePath(Optional<String> certificatePath);
48+
49+
public abstract SecurityConfig build();
50+
}
51+
52+
public static SecurityConfig.Builder newBuilder() {
53+
return new AutoValue_SecurityConfig.Builder()
54+
.setCredentials(Optional.empty())
55+
.setTLSEnabled(false)
56+
.setCertificatePath(Optional.empty());
57+
}
58+
}

0 commit comments

Comments
 (0)