Skip to content

Commit

Permalink
HDDS-11216. Replace HAUtils#buildCAX509List usages with other direct …
Browse files Browse the repository at this point in the history
…usages (#6981)
  • Loading branch information
Galsza authored Aug 27, 2024
1 parent 51a5fb9 commit dab1538
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 172 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

package org.apache.hadoop.hdds.security.x509.certificate.client;

import org.apache.hadoop.hdds.scm.client.ClientTrustManager;
import org.apache.hadoop.hdds.security.exception.OzoneSecurityException;
import org.apache.hadoop.hdds.security.ssl.ReloadingX509KeyManager;
import org.apache.hadoop.hdds.security.ssl.ReloadingX509TrustManager;
Expand Down Expand Up @@ -128,23 +129,6 @@ X509Certificate getCertificate(String certSerialId)
*/
Set<X509Certificate> getAllCaCerts();

/**
* Return the pem encoded CA certificate list.
* <p>
* If initialized return list of pem encoded CA certificates, else return
* null.
*
* @return list of pem encoded CA certificates.
*/
List<String> getCAList();

/**
* Update and returns the pem encoded CA certificate list.
* @return list of pem encoded CA certificates.
* @throws IOException
*/
List<String> updateCAList() throws IOException;

/**
* Verifies a digital Signature, given the signature and the certificate of
* the signer.
Expand Down Expand Up @@ -176,10 +160,32 @@ default void assertValidKeysAndCertificate() throws OzoneSecurityException {
}
}

/**
* Gets a KeyManager containing this CertificateClient's key material and trustchain.
* During certificate rotation this KeyManager is automatically updated with the new keys/certificates.
*
* @return A KeyManager containing keys and the trustchain for this CertificateClient.
* @throws CertificateException
*/
ReloadingX509KeyManager getKeyManager() throws CertificateException;

/**
* Gets a TrustManager containing the trusted certificates of this CertificateClient.
* During certificate rotation this TrustManager is automatically updated with the new certificates.
*
* @return A TrustManager containing trusted certificates for this CertificateClient.
* @throws CertificateException
*/
ReloadingX509TrustManager getTrustManager() throws CertificateException;

/**
* Creates a ClientTrustManager instance using the trusted certificates of this certificate client.
*
* @return The new ClientTrustManager instance.
* @throws IOException
*/
ClientTrustManager createClientTrustManager() throws IOException;

/**
* Register a receiver that will be called after the certificate renewed.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos.ContainerReportsProto;
import org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos.NodeReportProto;
import org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos.PipelineReportsProto;
import org.apache.hadoop.hdds.scm.client.ClientTrustManager;
import org.apache.hadoop.hdds.security.symmetric.SecretKeyClient;
import org.apache.hadoop.hdds.security.x509.certificate.client.CertificateClient;
import org.apache.hadoop.hdds.upgrade.HDDSLayoutVersionManager;
Expand Down Expand Up @@ -216,7 +217,7 @@ public DatanodeStateMachine(HddsDatanodeService hddsDatanodeService,
ReplicationSupervisorMetrics.create(supervisor);

ecReconstructionMetrics = ECReconstructionMetrics.create();

ClientTrustManager clientTrustManager = null;
ecReconstructionCoordinator = new ECReconstructionCoordinator(
conf, certClient, secretKeyClient, context, ecReconstructionMetrics,
threadNamePrefix);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,10 @@
import org.apache.hadoop.hdds.scm.XceiverClientManager;
import org.apache.hadoop.hdds.scm.XceiverClientSpi;
import org.apache.hadoop.hdds.scm.client.ClientTrustManager;
import org.apache.hadoop.hdds.security.x509.certificate.client.CACertificateProvider;
import org.apache.hadoop.hdds.scm.pipeline.Pipeline;
import org.apache.hadoop.hdds.scm.pipeline.PipelineID;
import org.apache.hadoop.hdds.scm.storage.ContainerProtocolCalls;
import org.apache.hadoop.hdds.security.x509.certificate.client.CertificateClient;
import org.apache.hadoop.hdds.utils.HAUtils;
import org.apache.hadoop.ozone.OzoneSecurityUtil;
import org.apache.hadoop.ozone.container.common.helpers.BlockData;
import org.apache.hadoop.security.token.Token;
Expand Down Expand Up @@ -69,21 +67,17 @@ public ECContainerOperationClient(ConfigurationSource conf,
}

@Nonnull
private static XceiverClientManager createClientManager(
ConfigurationSource conf, CertificateClient certificateClient)
private static XceiverClientManager createClientManager(ConfigurationSource conf, CertificateClient certificateClient)
throws IOException {
ClientTrustManager trustManager = null;
if (OzoneSecurityUtil.isSecurityEnabled(conf)) {
CACertificateProvider localCaCerts =
() -> HAUtils.buildCAX509List(certificateClient, conf);
CACertificateProvider remoteCacerts =
() -> HAUtils.buildCAX509List(null, conf);
trustManager = new ClientTrustManager(remoteCacerts, localCaCerts);
trustManager = certificateClient.createClientTrustManager();
}
return new XceiverClientManager(conf,
new XceiverClientManager.XceiverClientManagerConfigBuilder()
.setMaxCacheSize(256).setStaleThresholdMs(10 * 1000).build(),
trustManager);
XceiverClientManager.ScmClientConfig scmClientConfig = new XceiverClientManager.XceiverClientManagerConfigBuilder()
.setMaxCacheSize(256)
.setStaleThresholdMs(10 * 1000)
.build();
return new XceiverClientManager(conf, scmClientConfig, trustManager);
}

public BlockData[] listBlock(long containerId, DatanodeDetails dn,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
import org.apache.commons.io.FileUtils;
import org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetCertResponseProto;
import org.apache.hadoop.hdds.protocolPB.SCMSecurityProtocolClientSideTranslatorPB;
import org.apache.hadoop.hdds.scm.client.ClientTrustManager;
import org.apache.hadoop.hdds.security.SecurityConfig;
import org.apache.hadoop.hdds.security.ssl.ReloadingX509KeyManager;
import org.apache.hadoop.hdds.security.ssl.ReloadingX509TrustManager;
Expand Down Expand Up @@ -983,43 +984,6 @@ public Set<X509Certificate> getAllCaCerts() {
return certs;
}

@Override
public List<String> getCAList() {
pemEncodedCACertsLock.lock();
try {
return pemEncodedCACerts;
} finally {
pemEncodedCACertsLock.unlock();
}
}

public List<String> listCA() throws IOException {
pemEncodedCACertsLock.lock();
try {
if (pemEncodedCACerts == null) {
updateCAList();
}
return pemEncodedCACerts;
} finally {
pemEncodedCACertsLock.unlock();
}
}

@Override
public List<String> updateCAList() throws IOException {
pemEncodedCACertsLock.lock();
try {
pemEncodedCACerts = getScmSecureClient().listCACertificate();
return pemEncodedCACerts;
} catch (Exception e) {
getLogger().error("Error during updating CA list", e);
throw new CertificateException("Error during updating CA list", e,
CERTIFICATE_ERROR);
} finally {
pemEncodedCACertsLock.unlock();
}
}

@Override
public ReloadingX509TrustManager getTrustManager() throws CertificateException {
try {
Expand Down Expand Up @@ -1049,8 +1013,20 @@ public ReloadingX509KeyManager getKeyManager() throws CertificateException {
}
}

@Override
public ClientTrustManager createClientTrustManager() throws IOException {
CACertificateProvider caCertificateProvider = () -> {
List<X509Certificate> caCerts = new ArrayList<>();
caCerts.addAll(getAllCaCerts());
caCerts.addAll(getAllRootCaCerts());
return caCerts;
};
return new ClientTrustManager(caCertificateProvider, caCertificateProvider);
}

/**
* Register a receiver that will be called after the certificate renewed.
*
* @param receiver
*/
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@
import org.apache.hadoop.hdds.scm.proxy.SCMClientConfig;
import org.apache.hadoop.hdds.scm.proxy.SCMContainerLocationFailoverProxyProvider;
import org.apache.hadoop.hdds.security.exception.SCMSecurityException;
import org.apache.hadoop.hdds.security.x509.certificate.client.CertificateClient;
import org.apache.hadoop.hdds.security.x509.certificate.utils.CertificateCodec;
import org.apache.hadoop.hdds.tracing.TracingUtil;
import org.apache.hadoop.hdds.utils.db.DBDefinition;
import org.apache.hadoop.hdds.utils.db.DBColumnFamilyDefinition;
Expand Down Expand Up @@ -373,80 +371,6 @@ public static List<String> getExistingSstFiles(File db) throws IOException {
return sstList;
}

/**
* Build CA list which need to be passed to client.
*
* If certificate client is null, obtain the list of CA using SCM security
* client, else it uses certificate client.
* @return list of CA
*/
public static List<String> buildCAList(CertificateClient certClient,
ConfigurationSource configuration) throws IOException {
long waitDuration =
configuration.getTimeDuration(OZONE_SCM_CA_LIST_RETRY_INTERVAL,
OZONE_SCM_CA_LIST_RETRY_INTERVAL_DEFAULT, TimeUnit.SECONDS);
if (certClient != null) {
if (!SCMHAUtils.isSCMHAEnabled(configuration)) {
return generateCAList(certClient);
} else {
Collection<String> scmNodes = SCMHAUtils.getSCMNodeIds(configuration);
int expectedCount = scmNodes.size() + 1;
if (scmNodes.size() > 1) {
// First check if cert client has ca list initialized.
// This is being done, when this method is called multiple times we
// don't make call to SCM, we return from in-memory.
List<String> caCertPemList = certClient.getCAList();
if (caCertPemList != null && caCertPemList.size() == expectedCount) {
return caCertPemList;
}
return getCAListWithRetry(() ->
waitForCACerts(certClient::updateCAList, expectedCount),
waitDuration);
} else {
return generateCAList(certClient);
}
}
} else {
SCMSecurityProtocolClientSideTranslatorPB scmSecurityProtocolClient =
HddsServerUtil.getScmSecurityClient(configuration);
if (!SCMHAUtils.isSCMHAEnabled(configuration)) {
List<String> caCertPemList = new ArrayList<>();
SCMGetCertResponseProto scmGetCertResponseProto =
scmSecurityProtocolClient.getCACert();
if (scmGetCertResponseProto.hasX509Certificate()) {
caCertPemList.add(scmGetCertResponseProto.getX509Certificate());
}
if (scmGetCertResponseProto.hasX509RootCACertificate()) {
caCertPemList.add(scmGetCertResponseProto.getX509RootCACertificate());
}
return caCertPemList;
} else {
Collection<String> scmNodes = SCMHAUtils.getSCMNodeIds(configuration);
int expectedCount = scmNodes.size() + 1;
if (scmNodes.size() > 1) {
return getCAListWithRetry(() -> waitForCACerts(
scmSecurityProtocolClient::listCACertificate,
expectedCount), waitDuration);
} else {
return scmSecurityProtocolClient.listCACertificate();
}
}
}
}

private static List<String> generateCAList(CertificateClient certClient)
throws IOException {
List<String> caCertPemList = new ArrayList<>();
for (X509Certificate cert : certClient.getAllRootCaCerts()) {
caCertPemList.add(CertificateCodec.getPEMEncodedString(cert));
}
for (X509Certificate cert : certClient.getAllCaCerts()) {
caCertPemList.add(CertificateCodec.getPEMEncodedString(cert));
}
return caCertPemList;
}


/**
* Retry forever until CA list matches expected count.
* @param task - task to get CA list.
Expand Down Expand Up @@ -488,23 +412,37 @@ private static List<String> waitForCACerts(
* Build CA List in the format of X509Certificate.
* If certificate client is null, obtain the list of CA using SCM
* security client, else it uses certificate client.
*
* @return list of CA X509Certificates.
*/
public static List<X509Certificate> buildCAX509List(
CertificateClient certClient,
ConfigurationSource conf) throws IOException {
if (certClient != null) {
// Do this here to avoid extra conversion of X509 to pem and again to
// X509 by buildCAList.
if (!SCMHAUtils.isSCMHAEnabled(conf)) {
List<X509Certificate> x509Certificates = new ArrayList<>();
x509Certificates.addAll(certClient.getAllCaCerts());
x509Certificates.addAll(certClient.getAllRootCaCerts());
return x509Certificates;
public static List<X509Certificate> buildCAX509List(ConfigurationSource conf) throws IOException {
long waitDuration =
conf.getTimeDuration(OZONE_SCM_CA_LIST_RETRY_INTERVAL,
OZONE_SCM_CA_LIST_RETRY_INTERVAL_DEFAULT, TimeUnit.SECONDS);
Collection<String> scmNodes = SCMHAUtils.getSCMNodeIds(conf);
SCMSecurityProtocolClientSideTranslatorPB scmSecurityProtocolClient =
HddsServerUtil.getScmSecurityClient(conf);
if (!SCMHAUtils.isSCMHAEnabled(conf)) {
List<String> caCertPemList = new ArrayList<>();
SCMGetCertResponseProto scmGetCertResponseProto =
scmSecurityProtocolClient.getCACert();
if (scmGetCertResponseProto.hasX509Certificate()) {
caCertPemList.add(scmGetCertResponseProto.getX509Certificate());
}
if (scmGetCertResponseProto.hasX509RootCACertificate()) {
caCertPemList.add(scmGetCertResponseProto.getX509RootCACertificate());
}
return OzoneSecurityUtil.convertToX509(caCertPemList);
} else {
int expectedCount = scmNodes.size() + 1;
if (scmNodes.size() > 1) {
return OzoneSecurityUtil.convertToX509(getCAListWithRetry(() -> waitForCACerts(
scmSecurityProtocolClient::listCACertificate,
expectedCount), waitDuration));
} else {
return OzoneSecurityUtil.convertToX509(scmSecurityProtocolClient.listCACertificate());
}
}
List<String> pemEncodedCerts = HAUtils.buildCAList(certClient, conf);
return OzoneSecurityUtil.convertToX509(pemEncodedCerts);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.scm.client.ClientTrustManager;
import org.apache.hadoop.hdds.security.exception.SCMSecurityException;
import org.apache.hadoop.hdds.security.SecurityConfig;
import org.apache.hadoop.hdds.security.ssl.ReloadingX509KeyManager;
Expand Down Expand Up @@ -257,16 +258,6 @@ public Set<X509Certificate> getAllCaCerts() {
return rootCerts;
}

@Override
public List<String> getCAList() {
return null;
}

@Override
public List<String> updateCAList() throws IOException {
return null;
}

public void renewRootCA() throws Exception {
LocalDateTime start = LocalDateTime.now();
Duration rootCACertDuration = securityConfig.getMaxCertificateDuration();
Expand Down Expand Up @@ -364,6 +355,17 @@ public ReloadingX509TrustManager getTrustManager() throws CertificateException {
}
}

@Override
public ClientTrustManager createClientTrustManager() throws IOException {
CACertificateProvider caCertificateProvider = () -> {
List<X509Certificate> caCerts = new ArrayList<>();
caCerts.addAll(getAllCaCerts());
caCerts.addAll(getAllRootCaCerts());
return caCerts;
};
return new ClientTrustManager(caCertificateProvider, caCertificateProvider);
}

@Override
public void registerNotificationReceiver(CertificateNotification receiver) {
synchronized (notificationReceivers) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1613,8 +1613,7 @@ private void persistSCMCertificates() throws IOException {
if (primaryScmNodeId != null && !primaryScmNodeId.equals(
scmStorageConfig.getScmId())) {
List<String> pemEncodedCerts =
scmCertificateClient.listCA();

getScmSecurityClientWithMaxRetry(configuration, getCurrentUser()).listCACertificate();
// Write the primary SCM CA and Root CA during startup.
for (String cert : pemEncodedCerts) {
X509Certificate x509Certificate = CertificateCodec.getX509Certificate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ private XceiverClientManager newXCeiverClientManager(ConfigurationSource conf)
throws IOException {
XceiverClientManager manager;
if (OzoneSecurityUtil.isSecurityEnabled(conf)) {
CACertificateProvider caCerts = () -> HAUtils.buildCAX509List(null, conf);
CACertificateProvider caCerts = () -> HAUtils.buildCAX509List(conf);
manager = new XceiverClientManager(conf,
conf.getObject(XceiverClientManager.ScmClientConfig.class),
new ClientTrustManager(caCerts, null));
Expand Down
Loading

0 comments on commit dab1538

Please sign in to comment.