Skip to content

Commit c408f6e

Browse files
authored
HDDS-15094. Make protocol and cipher configurable for gRPC TLS (#10114)
Generated-by: Claude - Opus 4.6
1 parent 0f82ff6 commit c408f6e

9 files changed

Lines changed: 408 additions & 0 deletions

File tree

hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,9 @@ public final class HddsConfigKeys {
292292
".test.cert";
293293
public static final boolean HDDS_GRPC_TLS_TEST_CERT_DEFAULT = false;
294294

295+
public static final String HDDS_GRPC_TLS_PROTOCOLS = "hdds.grpc.tls.protocols";
296+
public static final String HDDS_GRPC_TLS_CIPHERS = "hdds.grpc.tls.ciphers";
297+
295298
// Comma separated acls (users, groups) allowing clients accessing
296299
// datanode container protocol
297300
// when hadoop.security.authorization is true, this needs to be set in

hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/SecurityConfig.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@
2424
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_DEFAULT_KEY_ALGORITHM;
2525
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_DEFAULT_KEY_LEN;
2626
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_DEFAULT_SECURITY_PROVIDER;
27+
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_GRPC_TLS_CIPHERS;
2728
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_GRPC_TLS_ENABLED;
2829
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_GRPC_TLS_ENABLED_DEFAULT;
30+
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_GRPC_TLS_PROTOCOLS;
2931
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_GRPC_TLS_PROVIDER;
3032
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_GRPC_TLS_PROVIDER_DEFAULT;
3133
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_GRPC_TLS_TEST_CERT;
@@ -83,10 +85,14 @@
8385
import java.security.Provider;
8486
import java.security.Security;
8587
import java.time.Duration;
88+
import java.util.Arrays;
89+
import java.util.Collections;
90+
import java.util.List;
8691
import java.util.Objects;
8792
import java.util.concurrent.TimeUnit;
8893
import java.util.regex.Matcher;
8994
import java.util.regex.Pattern;
95+
import org.apache.commons.lang3.StringUtils;
9096
import org.apache.hadoop.hdds.HddsConfigKeys;
9197
import org.apache.hadoop.hdds.conf.ConfigurationSource;
9298
import org.apache.hadoop.hdds.security.x509.keys.KeyCodec;
@@ -144,6 +150,8 @@ public class SecurityConfig {
144150
Pattern.compile("\\d{2}:\\d{2}:\\d{2}");
145151
private final Duration caAckTimeout;
146152
private final SslProvider grpcSSLProvider;
153+
private final String[] grpcTlsProtocols;
154+
private final List<String> grpcTlsCiphers;
147155
private final Duration rootCaCertificatePollingInterval;
148156
private final boolean autoCARotationEnabled;
149157
private final Duration expiredCertificateCheckInterval;
@@ -282,6 +290,18 @@ public SecurityConfig(ConfigurationSource configuration) {
282290
this.grpcSSLProvider = SslProvider.valueOf(
283291
configuration.get(HDDS_GRPC_TLS_PROVIDER,
284292
HDDS_GRPC_TLS_PROVIDER_DEFAULT));
293+
294+
String protocolsValue = configuration.get(HDDS_GRPC_TLS_PROTOCOLS);
295+
this.grpcTlsProtocols =
296+
StringUtils.isBlank(protocolsValue)
297+
? null
298+
: configuration.getTrimmedStrings(HDDS_GRPC_TLS_PROTOCOLS);
299+
300+
String ciphersValue = configuration.get(HDDS_GRPC_TLS_CIPHERS);
301+
this.grpcTlsCiphers =
302+
StringUtils.isBlank(ciphersValue)
303+
? null
304+
: Collections.unmodifiableList(Arrays.asList(configuration.getTrimmedStrings(HDDS_GRPC_TLS_CIPHERS)));
285305
}
286306

287307
public static synchronized void initSecurityProvider(ConfigurationSource configuration) {
@@ -572,6 +592,22 @@ public SslProvider getGrpcSslProvider() {
572592
return grpcSSLProvider;
573593
}
574594

595+
/**
596+
* Returns TLS protocol versions for gRPC servers,
597+
* or null for provider defaults.
598+
*/
599+
public String[] getGrpcTlsProtocols() {
600+
return grpcTlsProtocols == null ? null : Arrays.copyOf(grpcTlsProtocols, grpcTlsProtocols.length);
601+
}
602+
603+
/**
604+
* Returns TLS cipher suites for gRPC servers,
605+
* or null for provider defaults.
606+
*/
607+
public List<String> getGrpcTlsCiphers() {
608+
return grpcTlsCiphers;
609+
}
610+
575611
public boolean useExternalCACertificate(String component) {
576612
return component.equals(OzoneConsts.SCM_ROOT_CA_COMPONENT_NAME) &&
577613
!externalRootCaCert.isEmpty() && externalRootCaPrivateKeyPath.getNameCount() != 0;

hadoop-hdds/common/src/main/resources/ozone-default.xml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2546,6 +2546,24 @@
25462546
<tag>OZONE, HDDS, SECURITY, TLS</tag>
25472547
<description>If HDDS GRPC server TLS is enabled.</description>
25482548
</property>
2549+
<property>
2550+
<name>hdds.grpc.tls.protocols</name>
2551+
<value></value>
2552+
<tag>OZONE, HDDS, SECURITY, TLS, CRYPTO_COMPLIANCE</tag>
2553+
<description>Comma-separated list of TLS protocol versions for gRPC
2554+
server endpoints (e.g. "TLSv1.3" or "TLSv1.2,TLSv1.3"). When empty,
2555+
the TLS provider's defaults are used. Applies to server endpoints
2556+
only; clients are not restricted.</description>
2557+
</property>
2558+
<property>
2559+
<name>hdds.grpc.tls.ciphers</name>
2560+
<value></value>
2561+
<tag>OZONE, HDDS, SECURITY, TLS, CRYPTO_COMPLIANCE</tag>
2562+
<description>Comma-separated list of TLS cipher suites for gRPC server
2563+
endpoints (e.g. "TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256").
2564+
When empty, the TLS provider's defaults are used. Applies to server
2565+
endpoints only; clients are not restricted.</description>
2566+
</property>
25492567
<property>
25502568
<name>hdds.x509.default.duration</name>
25512569
<value>P365D</value>
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://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+
18+
package org.apache.hadoop.hdds.security;
19+
20+
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_GRPC_TLS_CIPHERS;
21+
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_GRPC_TLS_PROTOCOLS;
22+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
23+
import static org.junit.jupiter.api.Assertions.assertEquals;
24+
import static org.junit.jupiter.api.Assertions.assertNull;
25+
26+
import java.util.Arrays;
27+
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
28+
import org.junit.jupiter.api.Test;
29+
30+
/**
31+
* Tests for SecurityConfig TLS protocol and cipher suite parsing.
32+
*/
33+
public class TestSecurityConfigTlsSettings {
34+
35+
@Test
36+
public void testProtocolsDefault() {
37+
OzoneConfiguration conf = new OzoneConfiguration();
38+
SecurityConfig secConf = new SecurityConfig(conf);
39+
assertNull(secConf.getGrpcTlsProtocols());
40+
}
41+
42+
@Test
43+
public void testProtocolsSingle() {
44+
OzoneConfiguration conf = new OzoneConfiguration();
45+
conf.set(HDDS_GRPC_TLS_PROTOCOLS, "TLSv1.3");
46+
SecurityConfig secConf = new SecurityConfig(conf);
47+
assertArrayEquals(new String[]{"TLSv1.3"}, secConf.getGrpcTlsProtocols());
48+
}
49+
50+
@Test
51+
public void testProtocolsMultiple() {
52+
OzoneConfiguration conf = new OzoneConfiguration();
53+
conf.set(HDDS_GRPC_TLS_PROTOCOLS, "TLSv1.2,TLSv1.3");
54+
SecurityConfig secConf = new SecurityConfig(conf);
55+
assertArrayEquals(new String[]{"TLSv1.2", "TLSv1.3"}, secConf.getGrpcTlsProtocols());
56+
}
57+
58+
@Test
59+
public void testProtocolsWhitespaceTrimmed() {
60+
OzoneConfiguration conf = new OzoneConfiguration();
61+
conf.set(HDDS_GRPC_TLS_PROTOCOLS, " TLSv1.3 , TLSv1.2 ");
62+
SecurityConfig secConf = new SecurityConfig(conf);
63+
assertArrayEquals(new String[]{"TLSv1.3", "TLSv1.2"}, secConf.getGrpcTlsProtocols());
64+
}
65+
66+
@Test
67+
public void testProtocolsEmptyValue() {
68+
OzoneConfiguration conf = new OzoneConfiguration();
69+
conf.set(HDDS_GRPC_TLS_PROTOCOLS, "");
70+
SecurityConfig secConf = new SecurityConfig(conf);
71+
assertNull(secConf.getGrpcTlsProtocols());
72+
}
73+
74+
@Test
75+
public void testCiphersDefault() {
76+
OzoneConfiguration conf = new OzoneConfiguration();
77+
SecurityConfig secConf = new SecurityConfig(conf);
78+
assertNull(secConf.getGrpcTlsCiphers());
79+
}
80+
81+
@Test
82+
public void testCiphersMultiple() {
83+
OzoneConfiguration conf = new OzoneConfiguration();
84+
conf.set(HDDS_GRPC_TLS_CIPHERS, "TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256");
85+
SecurityConfig secConf = new SecurityConfig(conf);
86+
assertEquals(
87+
Arrays.asList("TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256"),
88+
secConf.getGrpcTlsCiphers());
89+
}
90+
}

hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/transport/server/XceiverServerGrpc.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ public XceiverServerGrpc(DatanodeDetails datanodeDetails,
145145
caClient.getKeyManager());
146146
SslContextBuilder sslContextBuilder = GrpcSslContexts.configure(
147147
sslClientContextBuilder, secConf.getGrpcSslProvider());
148+
sslContextBuilder.protocols(secConf.getGrpcTlsProtocols());
149+
sslContextBuilder.ciphers(secConf.getGrpcTlsCiphers());
148150
nettyServerBuilder.sslContext(sslContextBuilder.build());
149151
} catch (Exception ex) {
150152
LOG.error("Unable to setup TLS for secure datanode GRPC endpoint.", ex);

hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/replication/ReplicationServer.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ public void init() {
120120

121121
sslContextBuilder.clientAuth(ClientAuth.REQUIRE);
122122
sslContextBuilder.trustManager(caClient.getTrustManager());
123+
sslContextBuilder.protocols(secConf.getGrpcTlsProtocols());
124+
sslContextBuilder.ciphers(secConf.getGrpcTlsCiphers());
123125

124126
nettyServerBuilder.sslContext(sslContextBuilder.build());
125127
} catch (IOException ex) {

0 commit comments

Comments
 (0)