1414package io .dapr .utils ;
1515
1616import io .dapr .config .Properties ;
17+ import io .dapr .exceptions .DaprError ;
18+ import io .dapr .exceptions .DaprException ;
19+ import io .grpc .ChannelCredentials ;
1720import io .grpc .ClientInterceptor ;
21+ import io .grpc .Grpc ;
1822import io .grpc .ManagedChannel ;
1923import 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 ;
2028
29+ import java .io .FileInputStream ;
2130import java .io .IOException ;
31+ import java .io .InputStream ;
2232import java .net .InetAddress ;
2333import java .net .InetSocketAddress ;
2434import java .net .Socket ;
2535import java .util .regex .Pattern ;
2636
2737import static io .dapr .config .Properties .GRPC_ENDPOINT ;
2838import 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 ;
2943import static io .dapr .config .Properties .SIDECAR_IP ;
3044
31-
3245/**
3346 * Utility methods for network, internal to Dapr SDK.
3447 */
@@ -56,19 +69,20 @@ public final class NetworkUtils {
5669 private static final String GRPC_ENDPOINT_HOSTNAME_REGEX_PART = "(([A-Za-z0-9_\\ -\\ .]+)|(\\ [" + IPV6_REGEX + "\\ ]))" ;
5770
5871 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]+)?/" ;
6074
6175 private static final String GRPC_ENDPOINT_PARAM_REGEX_PART = "(\\ ?(?<param>tls\\ =((true)|(false))))?" ;
6276
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 + ")" ;
6579
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]+))?" ;
7286
7387 private static final String GRPC_ENDPOINT_REGEX = "^("
7488 + "(" + GRPC_ENDPOINT_HOST_REGEX_PART + ")|"
@@ -107,17 +121,76 @@ public static void waitForSocket(String host, int port, int timeoutInMillisecond
107121
108122 /**
109123 * Creates a GRPC managed channel.
110- * @param properties instance to set up the GrpcEndpoint
124+ *
125+ * @param properties instance to set up the GrpcEndpoint
111126 * @param interceptors Optional interceptors to add to the channel.
112127 * @return GRPC managed channel to communicate with the sidecar.
113128 */
114129 public static ManagedChannel buildGrpcManagedChannel (Properties properties , ClientInterceptor ... interceptors ) {
115130 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 ) {
119189 builder = builder .usePlaintext ();
120190 }
191+
192+ builder .userAgent (Version .getSdkVersion ());
193+
121194 if (interceptors != null && interceptors .length > 0 ) {
122195 builder = builder .intercept (interceptors );
123196 }
@@ -128,15 +201,26 @@ public static ManagedChannel buildGrpcManagedChannel(Properties properties, Clie
128201 static final class GrpcEndpointSettings {
129202 final String endpoint ;
130203 final boolean secure ;
204+ final String tlsPrivateKeyPath ;
205+ final String tlsCertPath ;
206+ final String tlsCaPath ;
131207
132- private GrpcEndpointSettings (String endpoint , boolean secure ) {
208+ private GrpcEndpointSettings (
209+ String endpoint , boolean secure , String tlsPrivateKeyPath , String tlsCertPath , String tlsCaPath ) {
133210 this .endpoint = endpoint ;
134211 this .secure = secure ;
212+ this .tlsPrivateKeyPath = tlsPrivateKeyPath ;
213+ this .tlsCertPath = tlsCertPath ;
214+ this .tlsCaPath = tlsCaPath ;
135215 }
136216
137217 static GrpcEndpointSettings parse (Properties properties ) {
138218 String address = properties .getValue (SIDECAR_IP );
139219 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+
140224 boolean secure = false ;
141225 String grpcEndpoint = properties .getValue (GRPC_ENDPOINT );
142226 if ((grpcEndpoint != null ) && !grpcEndpoint .isEmpty ()) {
@@ -172,21 +256,31 @@ static GrpcEndpointSettings parse(Properties properties) {
172256
173257 var authorityEndpoint = matcher .group ("authorityEndpoint" );
174258 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 );
176266 }
177267
178268 var socket = matcher .group ("socket" );
179269 if (socket != null ) {
180- return new GrpcEndpointSettings (socket , secure );
270+ return new GrpcEndpointSettings (socket , secure , clientKeyPath , clientCertPath , caCertPath );
181271 }
182272
183273 var vsocket = matcher .group ("vsocket" );
184274 if (vsocket != null ) {
185- return new GrpcEndpointSettings (vsocket , secure );
275+ return new GrpcEndpointSettings (vsocket , secure , clientKeyPath , clientCertPath , caCertPath );
186276 }
187277 }
188278
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 );
190284 }
191285
192286 }
0 commit comments