This is an automated email from the ASF dual-hosted git repository.

pifta pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git


The following commit(s) were added to refs/heads/master by this push:
     new 61df5bf9e8 HDDS-9013. Fetch root CA certificate list during SCM 
startup. (#5150)
61df5bf9e8 is described below

commit 61df5bf9e8ea72ee68fedca411c66c603c4c6601
Author: Sammi Chen <[email protected]>
AuthorDate: Wed Aug 9 21:28:59 2023 +0800

    HDDS-9013. Fetch root CA certificate list during SCM startup. (#5150)
---
 .../client/DefaultCertificateClient.java           | 25 ++++++--
 .../certificate/client/SCMCertificateClient.java   | 74 +++++++++++++++++++++-
 .../hdds/scm/server/StorageContainerManager.java   | 18 +++---
 3 files changed, 101 insertions(+), 16 deletions(-)

diff --git 
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/client/DefaultCertificateClient.java
 
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/client/DefaultCertificateClient.java
index a6583fc014..8cf5e9d50b 100644
--- 
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/client/DefaultCertificateClient.java
+++ 
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/client/DefaultCertificateClient.java
@@ -616,10 +616,15 @@ public abstract class DefaultCertificateClient implements 
CertificateClient {
         }
       }
 
-      codec.writeCertificate(certName,
-          pemEncodedCert);
+      codec.writeCertificate(certName, pemEncodedCert);
       if (addToCertMap) {
         certificateMap.put(cert.getSerialNumber().toString(), certificatePath);
+        if (caType == CAType.SUBORDINATE) {
+          caCertificates.add(cert);
+        }
+        if (caType == CAType.ROOT) {
+          rootCaCertificates.add(cert);
+        }
       }
     } catch (IOException | java.security.cert.CertificateException e) {
       throw new CertificateException("Error while storing certificate.", e,
@@ -975,6 +980,18 @@ public abstract class DefaultCertificateClient implements 
CertificateClient {
     }
   }
 
+  /**
+   * Notify all certificate renewal receivers that the certificate is renewed.
+   *
+   */
+  protected void notifyNotificationReceivers(String oldCaCertId,
+      String newCaCertId) {
+    synchronized (notificationReceivers) {
+      notificationReceivers.forEach(r -> r.notifyCertificateRenewed(
+          this, oldCaCertId, newCaCertId));
+    }
+  }
+
   @Override
   public synchronized void close() throws IOException {
     if (executorService != null) {
@@ -1215,9 +1232,7 @@ public abstract class DefaultCertificateClient implements 
CertificateClient {
     getLogger().info("Reset and reloaded key and all certificates for new " +
         "certificate {}.", newCertId);
 
-    // notify notification receivers
-    notificationReceivers.forEach(r -> r.notifyCertificateRenewed(
-        this, oldCaCertId, newCertId));
+    notifyNotificationReceivers(oldCaCertId, newCertId);
   }
 
   public SecurityConfig getSecurityConfig() {
diff --git 
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/client/SCMCertificateClient.java
 
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/client/SCMCertificateClient.java
index 15e6614cd0..357001b44b 100644
--- 
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/client/SCMCertificateClient.java
+++ 
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/client/SCMCertificateClient.java
@@ -18,6 +18,7 @@
 
 package org.apache.hadoop.hdds.security.x509.certificate.client;
 
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
 import 
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetCertResponseProto;
 import 
org.apache.hadoop.hdds.protocolPB.SCMSecurityProtocolClientSideTranslatorPB;
 import org.apache.hadoop.hdds.security.SecurityConfig;
@@ -27,14 +28,20 @@ import 
org.apache.hadoop.hdds.security.x509.certificate.utils.CertificateCodec;
 import 
org.apache.hadoop.hdds.security.x509.certificate.utils.CertificateSignRequest;
 import org.apache.hadoop.hdds.security.x509.exception.CertificateException;
 import org.apache.hadoop.ozone.OzoneConsts;
+import org.apache.hadoop.ozone.OzoneSecurityUtil;
 import org.bouncycastle.pkcs.PKCS10CertificationRequest;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.IOException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.security.KeyPair;
 import java.security.cert.X509Certificate;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
 import static 
org.apache.hadoop.hdds.security.x509.certificate.client.CertificateClient.InitResponse.FAILURE;
 import static 
org.apache.hadoop.hdds.security.x509.certificate.client.CertificateClient.InitResponse.GETCERT;
@@ -59,7 +66,7 @@ public class SCMCertificateClient extends 
DefaultCertificateClient {
   private String scmId;
   private String cId;
   private String scmHostname;
-  private SCMSecurityProtocolClientSideTranslatorPB scmSecurityClient;
+  private ExecutorService executorService;
 
   public SCMCertificateClient(SecurityConfig securityConfig,
       SCMSecurityProtocolClientSideTranslatorPB scmClient,
@@ -228,4 +235,69 @@ public class SCMCertificateClient extends 
DefaultCertificateClient {
       throw new RuntimeException(e);
     }
   }
+
+  public void refreshCACertificates() throws IOException {
+    if (executorService == null) {
+      executorService = Executors.newSingleThreadExecutor(
+          new ThreadFactoryBuilder().setNameFormat(
+                  getComponentName() + "-refreshCACertificates")
+              .setDaemon(true).build());
+    }
+    executorService.execute(new RefreshCACertificates(getScmSecureClient()));
+  }
+
+  /**
+   * Task to refresh root CA certificates for SCM.
+   */
+  public class RefreshCACertificates implements Runnable {
+    private final SCMSecurityProtocolClientSideTranslatorPB scmSecureClient;
+
+    public RefreshCACertificates(
+        SCMSecurityProtocolClientSideTranslatorPB client) {
+      this.scmSecureClient = client;
+    }
+
+    @Override
+    public void run() {
+      try {
+        // In case root CA certificate is rotated during this SCM is offline
+        // period, fetch the new root CA list from leader SCM and refresh ratis
+        // server's tlsConfig.
+        List<String> rootCAPems = scmSecureClient.getAllRootCaCertificates();
+
+        // SCM certificate client currently sets root CA as CA cert
+        Set<X509Certificate> certList = getAllRootCaCerts();
+        certList = certList.isEmpty() ? getAllCaCerts() : certList;
+
+        List<X509Certificate> rootCAsFromLeaderSCM =
+            OzoneSecurityUtil.convertToX509(rootCAPems);
+        rootCAsFromLeaderSCM.removeAll(certList);
+
+        if (rootCAsFromLeaderSCM.isEmpty()) {
+          LOG.info("CA certificates are not changed.");
+          return;
+        }
+
+        for (X509Certificate cert : rootCAsFromLeaderSCM) {
+          LOG.info("Fetched new root CA certificate {} from leader SCM",
+              cert.getSerialNumber().toString());
+          storeCertificate(
+              CertificateCodec.getPEMEncodedString(cert), CAType.SUBORDINATE);
+        }
+        String scmCertId = getCertificate().getSerialNumber().toString();
+        notifyNotificationReceivers(scmCertId, scmCertId);
+      } catch (IOException e) {
+        LOG.error("Failed to refresh CA certificates", e);
+      }
+    }
+  }
+
+  @Override
+  public synchronized void close() throws IOException {
+    super.close();
+    if (executorService != null) {
+      executorService.shutdownNow();
+      executorService = null;
+    }
+  }
 }
diff --git 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/StorageContainerManager.java
 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/StorageContainerManager.java
index 3cb4fa8754..9f12993853 100644
--- 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/StorageContainerManager.java
+++ 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/StorageContainerManager.java
@@ -280,7 +280,7 @@ public final class StorageContainerManager extends 
ServiceRuntimeInfoImpl
   private ReplicationManager replicationManager;
 
   private SCMSafeModeManager scmSafeModeManager;
-  private CertificateClient scmCertificateClient;
+  private SCMCertificateClient scmCertificateClient;
   private RootCARotationManager rootCARotationManager;
   private ContainerTokenSecretManager containerTokenMgr;
 
@@ -956,15 +956,6 @@ public final class StorageContainerManager extends 
ServiceRuntimeInfoImpl
     return scmCertificateClient;
   }
 
-  @VisibleForTesting
-  public void setScmCertificateClient(CertificateClient client)
-      throws IOException {
-    if (scmCertificateClient != null) {
-      scmCertificateClient.close();
-    }
-    scmCertificateClient = client;
-  }
-
   public Clock getSystemClock() {
     return systemClock;
   }
@@ -1543,6 +1534,13 @@ public final class StorageContainerManager extends 
ServiceRuntimeInfoImpl
 
     // At this point leader is not known
     scmHAMetricsUpdate(null);
+
+    if (scmCertificateClient != null) {
+      // In case root CA certificate is rotated during this SCM is offline
+      // period, fetch the new root CA list from leader SCM and refresh ratis
+      // server's tlsConfig.
+      scmCertificateClient.refreshCACertificates();
+    }
   }
 
   /**


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to