Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,9 @@ public final class HddsConfigKeys {
".test.cert";
public static final boolean HDDS_GRPC_TLS_TEST_CERT_DEFAULT = false;

public static final String HDDS_GRPC_TLS_PROTOCOLS = "hdds.grpc.tls.protocols";
public static final String HDDS_GRPC_TLS_CIPHERS = "hdds.grpc.tls.ciphers";

// Comma separated acls (users, groups) allowing clients accessing
// datanode container protocol
// when hadoop.security.authorization is true, this needs to be set in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_DEFAULT_KEY_ALGORITHM;
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_DEFAULT_KEY_LEN;
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_DEFAULT_SECURITY_PROVIDER;
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_GRPC_TLS_CIPHERS;
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_GRPC_TLS_ENABLED;
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_GRPC_TLS_ENABLED_DEFAULT;
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_GRPC_TLS_PROTOCOLS;
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_GRPC_TLS_PROVIDER;
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_GRPC_TLS_PROVIDER_DEFAULT;
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_GRPC_TLS_TEST_CERT;
Expand Down Expand Up @@ -83,10 +85,14 @@
import java.security.Provider;
import java.security.Security;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.hdds.HddsConfigKeys;
import org.apache.hadoop.hdds.conf.ConfigurationSource;
import org.apache.hadoop.hdds.security.x509.keys.KeyCodec;
Expand Down Expand Up @@ -144,6 +150,8 @@ public class SecurityConfig {
Pattern.compile("\\d{2}:\\d{2}:\\d{2}");
private final Duration caAckTimeout;
private final SslProvider grpcSSLProvider;
private final String[] grpcTlsProtocols;
private final List<String> grpcTlsCiphers;
private final Duration rootCaCertificatePollingInterval;
private final boolean autoCARotationEnabled;
private final Duration expiredCertificateCheckInterval;
Expand Down Expand Up @@ -282,6 +290,18 @@ public SecurityConfig(ConfigurationSource configuration) {
this.grpcSSLProvider = SslProvider.valueOf(
configuration.get(HDDS_GRPC_TLS_PROVIDER,
HDDS_GRPC_TLS_PROVIDER_DEFAULT));

String protocolsValue = configuration.get(HDDS_GRPC_TLS_PROTOCOLS);
this.grpcTlsProtocols =
StringUtils.isBlank(protocolsValue)
? null
: configuration.getTrimmedStrings(HDDS_GRPC_TLS_PROTOCOLS);

String ciphersValue = configuration.get(HDDS_GRPC_TLS_CIPHERS);
this.grpcTlsCiphers =
StringUtils.isBlank(ciphersValue)
? null
: Collections.unmodifiableList(Arrays.asList(configuration.getTrimmedStrings(HDDS_GRPC_TLS_CIPHERS)));
}

public static synchronized void initSecurityProvider(ConfigurationSource configuration) {
Expand Down Expand Up @@ -572,6 +592,22 @@ public SslProvider getGrpcSslProvider() {
return grpcSSLProvider;
}

/**
* Returns TLS protocol versions for gRPC servers,
* or null for provider defaults.
*/
public String[] getGrpcTlsProtocols() {
return grpcTlsProtocols == null ? null : Arrays.copyOf(grpcTlsProtocols, grpcTlsProtocols.length);
}

/**
* Returns TLS cipher suites for gRPC servers,
* or null for provider defaults.
*/
public List<String> getGrpcTlsCiphers() {
return grpcTlsCiphers;
}

public boolean useExternalCACertificate(String component) {
return component.equals(OzoneConsts.SCM_ROOT_CA_COMPONENT_NAME) &&
!externalRootCaCert.isEmpty() && externalRootCaPrivateKeyPath.getNameCount() != 0;
Expand Down
18 changes: 18 additions & 0 deletions hadoop-hdds/common/src/main/resources/ozone-default.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2546,6 +2546,24 @@
<tag>OZONE, HDDS, SECURITY, TLS</tag>
<description>If HDDS GRPC server TLS is enabled.</description>
</property>
<property>
<name>hdds.grpc.tls.protocols</name>
<value></value>
<tag>OZONE, HDDS, SECURITY, TLS, CRYPTO_COMPLIANCE</tag>
<description>Comma-separated list of TLS protocol versions for gRPC
server endpoints (e.g. "TLSv1.3" or "TLSv1.2,TLSv1.3"). When empty,
the TLS provider's defaults are used. Applies to server endpoints
only; clients are not restricted.</description>
</property>
<property>
<name>hdds.grpc.tls.ciphers</name>
<value></value>
<tag>OZONE, HDDS, SECURITY, TLS, CRYPTO_COMPLIANCE</tag>
<description>Comma-separated list of TLS cipher suites for gRPC server
endpoints (e.g. "TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256").
When empty, the TLS provider's defaults are used. Applies to server
endpoints only; clients are not restricted.</description>
</property>
<property>
<name>hdds.x509.default.duration</name>
<value>P365D</value>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.hadoop.hdds.security;

import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_GRPC_TLS_CIPHERS;
import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_GRPC_TLS_PROTOCOLS;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

import java.util.Arrays;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.junit.jupiter.api.Test;

/**
* Tests for SecurityConfig TLS protocol and cipher suite parsing.
*/
public class TestSecurityConfigTlsSettings {

@Test
public void testProtocolsDefault() {
OzoneConfiguration conf = new OzoneConfiguration();
SecurityConfig secConf = new SecurityConfig(conf);
assertNull(secConf.getGrpcTlsProtocols());
}

@Test
public void testProtocolsSingle() {
OzoneConfiguration conf = new OzoneConfiguration();
conf.set(HDDS_GRPC_TLS_PROTOCOLS, "TLSv1.3");
SecurityConfig secConf = new SecurityConfig(conf);
assertArrayEquals(new String[]{"TLSv1.3"}, secConf.getGrpcTlsProtocols());
}

@Test
public void testProtocolsMultiple() {
OzoneConfiguration conf = new OzoneConfiguration();
conf.set(HDDS_GRPC_TLS_PROTOCOLS, "TLSv1.2,TLSv1.3");
SecurityConfig secConf = new SecurityConfig(conf);
assertArrayEquals(new String[]{"TLSv1.2", "TLSv1.3"}, secConf.getGrpcTlsProtocols());
}

@Test
public void testProtocolsWhitespaceTrimmed() {
OzoneConfiguration conf = new OzoneConfiguration();
conf.set(HDDS_GRPC_TLS_PROTOCOLS, " TLSv1.3 , TLSv1.2 ");
SecurityConfig secConf = new SecurityConfig(conf);
assertArrayEquals(new String[]{"TLSv1.3", "TLSv1.2"}, secConf.getGrpcTlsProtocols());
}

@Test
public void testProtocolsEmptyValue() {
OzoneConfiguration conf = new OzoneConfiguration();
conf.set(HDDS_GRPC_TLS_PROTOCOLS, "");
SecurityConfig secConf = new SecurityConfig(conf);
assertNull(secConf.getGrpcTlsProtocols());
}

@Test
public void testCiphersDefault() {
OzoneConfiguration conf = new OzoneConfiguration();
SecurityConfig secConf = new SecurityConfig(conf);
assertNull(secConf.getGrpcTlsCiphers());
}

@Test
public void testCiphersMultiple() {
OzoneConfiguration conf = new OzoneConfiguration();
conf.set(HDDS_GRPC_TLS_CIPHERS, "TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256");
SecurityConfig secConf = new SecurityConfig(conf);
assertEquals(
Arrays.asList("TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256"),
secConf.getGrpcTlsCiphers());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ public XceiverServerGrpc(DatanodeDetails datanodeDetails,
caClient.getKeyManager());
SslContextBuilder sslContextBuilder = GrpcSslContexts.configure(
sslClientContextBuilder, secConf.getGrpcSslProvider());
sslContextBuilder.protocols(secConf.getGrpcTlsProtocols());
sslContextBuilder.ciphers(secConf.getGrpcTlsCiphers());
nettyServerBuilder.sslContext(sslContextBuilder.build());
} catch (Exception ex) {
LOG.error("Unable to setup TLS for secure datanode GRPC endpoint.", ex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ public void init() {

sslContextBuilder.clientAuth(ClientAuth.REQUIRE);
sslContextBuilder.trustManager(caClient.getTrustManager());
sslContextBuilder.protocols(secConf.getGrpcTlsProtocols());
sslContextBuilder.ciphers(secConf.getGrpcTlsCiphers());

nettyServerBuilder.sslContext(sslContextBuilder.build());
} catch (IOException ex) {
Expand Down
Loading