14
14
package io .dapr .utils ;
15
15
16
16
import io .dapr .config .Properties ;
17
+ import io .dapr .exceptions .DaprError ;
18
+ import io .dapr .exceptions .DaprException ;
19
+ import io .grpc .ChannelCredentials ;
17
20
import io .grpc .ClientInterceptor ;
21
+ import io .grpc .Grpc ;
18
22
import io .grpc .ManagedChannel ;
19
23
import io .grpc .ManagedChannelBuilder ;
24
+ import io .grpc .TlsChannelCredentials ;
25
+ import io .grpc .netty .shaded .io .grpc .netty .GrpcSslContexts ;
26
+ import io .grpc .netty .shaded .io .grpc .netty .NettyChannelBuilder ;
27
+ import io .grpc .netty .shaded .io .netty .handler .ssl .util .InsecureTrustManagerFactory ;
20
28
29
+ import java .io .FileInputStream ;
21
30
import java .io .IOException ;
31
+ import java .io .InputStream ;
22
32
import java .net .InetAddress ;
23
33
import java .net .InetSocketAddress ;
24
34
import java .net .Socket ;
25
35
import java .util .regex .Pattern ;
26
36
27
37
import static io .dapr .config .Properties .GRPC_ENDPOINT ;
28
38
import static io .dapr .config .Properties .GRPC_PORT ;
39
+ import static io .dapr .config .Properties .GRPC_TLS_CA_PATH ;
40
+ import static io .dapr .config .Properties .GRPC_TLS_CERT_PATH ;
41
+ import static io .dapr .config .Properties .GRPC_TLS_INSECURE ;
42
+ import static io .dapr .config .Properties .GRPC_TLS_KEY_PATH ;
29
43
import static io .dapr .config .Properties .SIDECAR_IP ;
30
44
31
-
32
45
/**
33
46
* Utility methods for network, internal to Dapr SDK.
34
47
*/
@@ -56,19 +69,20 @@ public final class NetworkUtils {
56
69
private static final String GRPC_ENDPOINT_HOSTNAME_REGEX_PART = "(([A-Za-z0-9_\\ -\\ .]+)|(\\ [" + IPV6_REGEX + "\\ ]))" ;
57
70
58
71
private static final String GRPC_ENDPOINT_DNS_AUTHORITY_REGEX_PART =
59
- "(?<dnsWithAuthority>dns://)(?<authorityEndpoint>" + GRPC_ENDPOINT_HOSTNAME_REGEX_PART + ":[0-9]+)?/" ;
72
+ "(?<dnsWithAuthority>dns://)(?<authorityEndpoint>"
73
+ + GRPC_ENDPOINT_HOSTNAME_REGEX_PART + ":[0-9]+)?/" ;
60
74
61
75
private static final String GRPC_ENDPOINT_PARAM_REGEX_PART = "(\\ ?(?<param>tls\\ =((true)|(false))))?" ;
62
76
63
- private static final String GRPC_ENDPOINT_SOCKET_REGEX_PART =
64
- "(?<socket>((unix:)|(unix://)|(unix-abstract:))" + GRPC_ENDPOINT_FILENAME_REGEX_PART + ")" ;
77
+ private static final String GRPC_ENDPOINT_SOCKET_REGEX_PART = "(?<socket>((unix:)|(unix://)|(unix-abstract:))"
78
+ + GRPC_ENDPOINT_FILENAME_REGEX_PART + ")" ;
65
79
66
- private static final String GRPC_ENDPOINT_VSOCKET_REGEX_PART =
67
- "(?<vsocket>vsock:" + GRPC_ENDPOINT_HOSTNAME_REGEX_PART + ":[0-9]+)" ;
68
- private static final String GRPC_ENDPOINT_HOST_REGEX_PART =
69
- "((?<http>http://)|(?<https>https://)|(?<dns>dns:)|(" + GRPC_ENDPOINT_DNS_AUTHORITY_REGEX_PART + "))?"
70
- + "(?<hostname>" + GRPC_ENDPOINT_HOSTNAME_REGEX_PART + ")?+"
71
- + "(:(?<port>[0-9]+))?" ;
80
+ private static final String GRPC_ENDPOINT_VSOCKET_REGEX_PART = "(?<vsocket>vsock:" + GRPC_ENDPOINT_HOSTNAME_REGEX_PART
81
+ + ":[0-9]+)" ;
82
+ private static final String GRPC_ENDPOINT_HOST_REGEX_PART = "((?<http>http://)|(?<https>https://)|(?<dns>dns:)|("
83
+ + GRPC_ENDPOINT_DNS_AUTHORITY_REGEX_PART + "))?"
84
+ + "(?<hostname>" + GRPC_ENDPOINT_HOSTNAME_REGEX_PART + ")?+"
85
+ + "(:(?<port>[0-9]+))?" ;
72
86
73
87
private static final String GRPC_ENDPOINT_REGEX = "^("
74
88
+ "(" + GRPC_ENDPOINT_HOST_REGEX_PART + ")|"
@@ -107,17 +121,76 @@ public static void waitForSocket(String host, int port, int timeoutInMillisecond
107
121
108
122
/**
109
123
* Creates a GRPC managed channel.
110
- * @param properties instance to set up the GrpcEndpoint
124
+ *
125
+ * @param properties instance to set up the GrpcEndpoint
111
126
* @param interceptors Optional interceptors to add to the channel.
112
127
* @return GRPC managed channel to communicate with the sidecar.
113
128
*/
114
129
public static ManagedChannel buildGrpcManagedChannel (Properties properties , ClientInterceptor ... interceptors ) {
115
130
var settings = GrpcEndpointSettings .parse (properties );
116
- ManagedChannelBuilder <?> builder = ManagedChannelBuilder .forTarget (settings .endpoint )
117
- .userAgent (Version .getSdkVersion ());
118
- if (!settings .secure ) {
131
+
132
+ boolean insecureTls = properties .getValue (GRPC_TLS_INSECURE );
133
+ if (insecureTls ) {
134
+ try {
135
+ ManagedChannelBuilder <?> builder = NettyChannelBuilder .forTarget (settings .endpoint )
136
+ .sslContext (GrpcSslContexts .forClient ()
137
+ .trustManager (InsecureTrustManagerFactory .INSTANCE )
138
+ .build ());
139
+ builder .userAgent (Version .getSdkVersion ());
140
+ if (interceptors != null && interceptors .length > 0 ) {
141
+ builder = builder .intercept (interceptors );
142
+ }
143
+ return builder .build ();
144
+ } catch (Exception e ) {
145
+ throw new DaprException (
146
+ new DaprError ().setErrorCode ("TLS_CREDENTIALS_ERROR" )
147
+ .setMessage ("Failed to create insecure TLS credentials" ), e );
148
+ }
149
+ }
150
+
151
+ String clientKeyPath = settings .tlsPrivateKeyPath ;
152
+ String clientCertPath = settings .tlsCertPath ;
153
+ String caCertPath = settings .tlsCaPath ;
154
+
155
+ ManagedChannelBuilder <?> builder = ManagedChannelBuilder .forTarget (settings .endpoint );
156
+
157
+ if (clientCertPath != null && clientKeyPath != null ) {
158
+ // mTLS case - using client cert and key, with optional CA cert for server authentication
159
+ try (
160
+ InputStream clientCertInputStream = new FileInputStream (clientCertPath );
161
+ InputStream clientKeyInputStream = new FileInputStream (clientKeyPath );
162
+ InputStream caCertInputStream = caCertPath != null ? new FileInputStream (caCertPath ) : null
163
+ ) {
164
+ TlsChannelCredentials .Builder builderCreds = TlsChannelCredentials .newBuilder ()
165
+ .keyManager (clientCertInputStream , clientKeyInputStream ); // For client authentication
166
+ if (caCertInputStream != null ) {
167
+ builderCreds .trustManager (caCertInputStream ); // For server authentication
168
+ }
169
+ ChannelCredentials credentials = builderCreds .build ();
170
+ builder = Grpc .newChannelBuilder (settings .endpoint , credentials );
171
+ } catch (IOException e ) {
172
+ throw new DaprException (
173
+ new DaprError ().setErrorCode ("TLS_CREDENTIALS_ERROR" )
174
+ .setMessage ("Failed to create mTLS credentials" + (caCertPath != null ? " with CA cert" : "" )), e );
175
+ }
176
+ } else if (caCertPath != null ) {
177
+ // Simple TLS case - using CA cert only for server authentication
178
+ try (InputStream caCertInputStream = new FileInputStream (caCertPath )) {
179
+ ChannelCredentials credentials = TlsChannelCredentials .newBuilder ()
180
+ .trustManager (caCertInputStream )
181
+ .build ();
182
+ builder = Grpc .newChannelBuilder (settings .endpoint , credentials );
183
+ } catch (IOException e ) {
184
+ throw new DaprException (
185
+ new DaprError ().setErrorCode ("TLS_CREDENTIALS_ERROR" )
186
+ .setMessage ("Failed to create TLS credentials with CA cert" ), e );
187
+ }
188
+ } else if (!settings .secure ) {
119
189
builder = builder .usePlaintext ();
120
190
}
191
+
192
+ builder .userAgent (Version .getSdkVersion ());
193
+
121
194
if (interceptors != null && interceptors .length > 0 ) {
122
195
builder = builder .intercept (interceptors );
123
196
}
@@ -128,15 +201,26 @@ public static ManagedChannel buildGrpcManagedChannel(Properties properties, Clie
128
201
static final class GrpcEndpointSettings {
129
202
final String endpoint ;
130
203
final boolean secure ;
204
+ final String tlsPrivateKeyPath ;
205
+ final String tlsCertPath ;
206
+ final String tlsCaPath ;
131
207
132
- private GrpcEndpointSettings (String endpoint , boolean secure ) {
208
+ private GrpcEndpointSettings (
209
+ String endpoint , boolean secure , String tlsPrivateKeyPath , String tlsCertPath , String tlsCaPath ) {
133
210
this .endpoint = endpoint ;
134
211
this .secure = secure ;
212
+ this .tlsPrivateKeyPath = tlsPrivateKeyPath ;
213
+ this .tlsCertPath = tlsCertPath ;
214
+ this .tlsCaPath = tlsCaPath ;
135
215
}
136
216
137
217
static GrpcEndpointSettings parse (Properties properties ) {
138
218
String address = properties .getValue (SIDECAR_IP );
139
219
int port = properties .getValue (GRPC_PORT );
220
+ String clientKeyPath = properties .getValue (GRPC_TLS_KEY_PATH );
221
+ String clientCertPath = properties .getValue (GRPC_TLS_CERT_PATH );
222
+ String caCertPath = properties .getValue (GRPC_TLS_CA_PATH );
223
+
140
224
boolean secure = false ;
141
225
String grpcEndpoint = properties .getValue (GRPC_ENDPOINT );
142
226
if ((grpcEndpoint != null ) && !grpcEndpoint .isEmpty ()) {
@@ -172,21 +256,31 @@ static GrpcEndpointSettings parse(Properties properties) {
172
256
173
257
var authorityEndpoint = matcher .group ("authorityEndpoint" );
174
258
if (authorityEndpoint != null ) {
175
- return new GrpcEndpointSettings (String .format ("dns://%s/%s:%d" , authorityEndpoint , address , port ), secure );
259
+ return new GrpcEndpointSettings (
260
+ String .format (
261
+ "dns://%s/%s:%d" ,
262
+ authorityEndpoint ,
263
+ address ,
264
+ port
265
+ ), secure , clientKeyPath , clientCertPath , caCertPath );
176
266
}
177
267
178
268
var socket = matcher .group ("socket" );
179
269
if (socket != null ) {
180
- return new GrpcEndpointSettings (socket , secure );
270
+ return new GrpcEndpointSettings (socket , secure , clientKeyPath , clientCertPath , caCertPath );
181
271
}
182
272
183
273
var vsocket = matcher .group ("vsocket" );
184
274
if (vsocket != null ) {
185
- return new GrpcEndpointSettings (vsocket , secure );
275
+ return new GrpcEndpointSettings (vsocket , secure , clientKeyPath , clientCertPath , caCertPath );
186
276
}
187
277
}
188
278
189
- return new GrpcEndpointSettings (String .format ("dns:///%s:%d" , address , port ), secure );
279
+ return new GrpcEndpointSettings (String .format (
280
+ "dns:///%s:%d" ,
281
+ address ,
282
+ port
283
+ ), secure , clientKeyPath , clientCertPath , caCertPath );
190
284
}
191
285
192
286
}
0 commit comments