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 a6ed346744 HDDS-8590. Implement a protocol call to get the rootCA from 
SCM (#4934)
a6ed346744 is described below

commit a6ed346744c69d19c1000cb0c3ad75d9dd4fe669
Author: Galsza <[email protected]>
AuthorDate: Wed Jun 21 23:20:42 2023 +0200

    HDDS-8590. Implement a protocol call to get the rootCA from SCM (#4934)
---
 .../hadoop/hdds/protocol/SCMSecurityProtocol.java  | 11 +++++-
 .../SCMSecurityProtocolClientSideTranslatorPB.java | 11 ++++++
 .../src/main/proto/ScmServerSecurityProtocol.proto | 14 ++++++-
 .../SCMSecurityProtocolServerSideTranslatorPB.java | 16 ++++++--
 .../hdds/scm/server/SCMSecurityProtocolServer.java | 46 +++++++++++++++++-----
 .../hdds/scm/server/StorageContainerManager.java   | 19 ++++++---
 .../scm/server/TestSCMSecurityProtocolServer.java  | 38 +++++++++++++++++-
 7 files changed, 132 insertions(+), 23 deletions(-)

diff --git 
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/protocol/SCMSecurityProtocol.java
 
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/protocol/SCMSecurityProtocol.java
index 2354a9b8d8..ed4906e3b7 100644
--- 
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/protocol/SCMSecurityProtocol.java
+++ 
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/protocol/SCMSecurityProtocol.java
@@ -164,11 +164,18 @@ public interface SCMSecurityProtocol {
    * Get SCM signed certificate.
    *
    * @param nodeDetails - Node Details.
-   * @param certSignReq  - Certificate signing request.
+   * @param certSignReq - Certificate signing request.
    * @return String      - pem encoded SCM signed
-   *                         certificate.
+   * certificate.
    */
   String getCertificate(NodeDetailsProto nodeDetails,
       String certSignReq) throws IOException;
 
+  /**
+   * Get all root CA certificates known to SCM.
+   *
+   * @return String     - pem encoded list of root CA certificates
+   */
+  List<String> getAllRootCaCertificates() throws IOException;
+
 }
diff --git 
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/protocolPB/SCMSecurityProtocolClientSideTranslatorPB.java
 
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/protocolPB/SCMSecurityProtocolClientSideTranslatorPB.java
index e3803c492a..32bdb2139a 100644
--- 
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/protocolPB/SCMSecurityProtocolClientSideTranslatorPB.java
+++ 
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/protocolPB/SCMSecurityProtocolClientSideTranslatorPB.java
@@ -32,6 +32,7 @@ import 
org.apache.hadoop.hdds.protocol.proto.HddsProtos.NodeDetailsProto;
 import 
org.apache.hadoop.hdds.protocol.proto.HddsProtos.OzoneManagerDetailsProto;
 import org.apache.hadoop.hdds.protocol.proto.HddsProtos.ScmNodeDetailsProto;
 import org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos;
+import 
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetAllRootCaCertificatesRequestProto;
 import 
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetSCMCertRequestProto;
 import 
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetCACertificateRequestProto;
 import 
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetCertResponseProto;
@@ -409,4 +410,14 @@ public class SCMSecurityProtocolClientSideTranslatorPB 
implements
   public Object getUnderlyingProxyObject() {
     return rpcProxy;
   }
+
+  @Override
+  public List<String> getAllRootCaCertificates() throws IOException {
+    SCMGetAllRootCaCertificatesRequestProto protoIns =
+        SCMGetAllRootCaCertificatesRequestProto.getDefaultInstance();
+    return submitRequest(Type.GetAllRootCaCertificates,
+        builder -> builder.setGetAllRootCaCertificatesRequestProto(protoIns))
+        .getAllRootCaCertificatesResponseProto()
+        .getAllX509RootCaCertificatesList();
+  }
 }
diff --git 
a/hadoop-hdds/interface-server/src/main/proto/ScmServerSecurityProtocol.proto 
b/hadoop-hdds/interface-server/src/main/proto/ScmServerSecurityProtocol.proto
index 1768444e07..85ae39379f 100644
--- 
a/hadoop-hdds/interface-server/src/main/proto/ScmServerSecurityProtocol.proto
+++ 
b/hadoop-hdds/interface-server/src/main/proto/ScmServerSecurityProtocol.proto
@@ -56,6 +56,8 @@ message SCMSecurityRequest {
     optional SCMGetLatestCrlIdRequestProto getLatestCrlIdRequest = 11;
     optional SCMRevokeCertificatesRequestProto revokeCertificatesRequest = 12;
     optional SCMGetCertRequestProto getCertRequest = 13;
+    optional SCMGetAllRootCaCertificatesRequestProto
+        getAllRootCaCertificatesRequestProto = 14;
 }
 
 message SCMSecurityResponse {
@@ -80,6 +82,8 @@ message SCMSecurityResponse {
     optional SCMGetLatestCrlIdResponseProto getLatestCrlIdResponseProto = 9;
 
     optional SCMRevokeCertificatesResponseProto 
revokeCertificatesResponseProto = 10;
+
+    optional SCMGetAllRootCaCertificatesResponseProto 
allRootCaCertificatesResponseProto = 11;
 }
 
 enum Type {
@@ -95,6 +99,7 @@ enum Type {
     GetLatestCrlId = 10;
     RevokeCertificates = 11;
     GetCert = 12;
+    GetAllRootCaCertificates = 13;
 }
 
 enum Status {
@@ -195,6 +200,10 @@ message SCMListCertificateResponseProto {
     repeated string certificates = 2;
 }
 
+message SCMGetAllRootCaCertificatesResponseProto {
+    repeated string allX509RootCaCertificates = 1;
+}
+
 message SCMGetRootCACertificateRequestProto {
 }
 
@@ -241,10 +250,13 @@ message SCMRevokeCertificatesRequestProto {
     optional uint64 revokeTime = 3;
 }
 
+message SCMGetAllRootCaCertificatesRequestProto {
+}
+
 message SCMRevokeCertificatesResponseProto {
     optional int64 crlId = 1;
 }
 
 service SCMSecurityProtocolService {
     rpc submitRequest (SCMSecurityRequest) returns (SCMSecurityResponse);
-}
\ No newline at end of file
+}
diff --git 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/protocol/SCMSecurityProtocolServerSideTranslatorPB.java
 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/protocol/SCMSecurityProtocolServerSideTranslatorPB.java
index 736aef15a0..d65eacc84c 100644
--- 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/protocol/SCMSecurityProtocolServerSideTranslatorPB.java
+++ 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/protocol/SCMSecurityProtocolServerSideTranslatorPB.java
@@ -21,6 +21,7 @@ import java.util.List;
 
 import org.apache.hadoop.hdds.protocol.SCMSecurityProtocol;
 import org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos;
+import 
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetAllRootCaCertificatesResponseProto;
 import 
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetCertResponseProto;
 import 
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetCertResponseProto.ResponseCode;
 import 
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.SCMGetCertificateRequestProto;
@@ -53,8 +54,6 @@ import com.google.protobuf.ServiceException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static 
org.apache.hadoop.hdds.protocol.proto.SCMSecurityProtocolProtos.Type.GetSCMCertificate;
-
 /**
  * This class is the server-side translator that forwards requests received on
  * {@link SCMSecurityProtocolPB} to the {@link
@@ -148,7 +147,11 @@ public class SCMSecurityProtocolServerSideTranslatorPB
             .build();
       case GetCert:
         return scmSecurityResponse.setGetCertResponseProto(
-            getCertificate(request.getGetCertRequest()))
+                getCertificate(request.getGetCertRequest()))
+            .build();
+      case GetAllRootCaCertificates:
+        return scmSecurityResponse
+            .setAllRootCaCertificatesResponseProto(getAllRootCa())
             .build();
 
       default:
@@ -397,6 +400,13 @@ public class SCMSecurityProtocolServerSideTranslatorPB
         ".scm.ratis.enable config");
   }
 
+  public SCMGetAllRootCaCertificatesResponseProto getAllRootCa()
+      throws IOException {
+    return SCMGetAllRootCaCertificatesResponseProto.newBuilder()
+        .addAllAllX509RootCaCertificates(impl.getAllRootCaCertificates())
+        .build();
+  }
+
   private void setRootCAIfNeeded(SCMGetCertResponseProto.Builder builder)
       throws IOException {
     if (scm.getScmStorageConfig().checkPrimarySCMIdInitialized()) {
diff --git 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMSecurityProtocolServer.java
 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMSecurityProtocolServer.java
index c8183ed0cb..c576875603 100644
--- 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMSecurityProtocolServer.java
+++ 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMSecurityProtocolServer.java
@@ -87,6 +87,7 @@ import static 
org.apache.hadoop.hdds.security.exception.SCMSecurityException.Err
 import static 
org.apache.hadoop.hdds.security.exception.SCMSecurityException.ErrorCode.GET_CA_CERT_FAILED;
 import static 
org.apache.hadoop.hdds.security.exception.SCMSecurityException.ErrorCode.GET_CERTIFICATE_FAILED;
 import static 
org.apache.hadoop.hdds.security.x509.certificate.authority.CertificateApprover.ApprovalType.KERBEROS_TRUSTED;
+import static 
org.apache.hadoop.hdds.security.x509.certificate.utils.CertificateCodec.getPEMEncodedString;
 
 /**
  * The protocol used to perform security related operations with SCM.
@@ -101,7 +102,7 @@ public class SCMSecurityProtocolServer implements 
SCMSecurityProtocol,
       .getLogger(SCMSecurityProtocolServer.class);
   private final CertificateServer rootCertificateServer;
   private final CertificateServer scmCertificateServer;
-  private final X509Certificate rootCACertificate;
+  private final List<X509Certificate> rootCACertificateList;
   private final RPC.Server rpcServer; // HADOOP RPC SERVER
   private final SCMUpdateServiceGrpcServer grpcUpdateServer; // gRPC SERVER
   private final InetSocketAddress rpcAddress;
@@ -116,13 +117,13 @@ public class SCMSecurityProtocolServer implements 
SCMSecurityProtocol,
   SCMSecurityProtocolServer(OzoneConfiguration conf,
       CertificateServer rootCertificateServer,
       CertificateServer scmCertificateServer,
-      X509Certificate rootCACert, StorageContainerManager scm,
+      List<X509Certificate> rootCACertList, StorageContainerManager scm,
       @Nullable SecretKeyManager secretKeyManager)
       throws IOException {
     this.storageContainerManager = scm;
     this.rootCertificateServer = rootCertificateServer;
     this.scmCertificateServer = scmCertificateServer;
-    this.rootCACertificate = rootCACert;
+    this.rootCACertificateList = rootCACertList;
     this.secretKeyManager = secretKeyManager;
     final int handlerCount =
         conf.getInt(ScmConfigKeys.OZONE_SCM_SECURITY_HANDLER_COUNT_KEY,
@@ -232,6 +233,17 @@ public class SCMSecurityProtocolServer implements 
SCMSecurityProtocol,
     }
   }
 
+  @Override
+  public synchronized List<String> getAllRootCaCertificates()
+      throws IOException {
+    List<String> pemEncodedList =
+        new ArrayList<>(rootCACertificateList.size());
+    for (X509Certificate cert : rootCACertificateList) {
+      pemEncodedList.add(getPEMEncodedString(cert));
+    }
+    return pemEncodedList;
+  }
+
   /**
    * Get SCM signed certificate for OM.
    *
@@ -292,7 +304,7 @@ public class SCMSecurityProtocolServer implements 
SCMSecurityProtocol,
           KERBEROS_TRUSTED, nodeType);
     }
     try {
-      return CertificateCodec.getPEMEncodedString(future.get());
+      return getPEMEncodedString(future.get());
     } catch (InterruptedException e) {
       Thread.currentThread().interrupt();
       throw generateException(e, nodeType);
@@ -339,7 +351,7 @@ public class SCMSecurityProtocolServer implements 
SCMSecurityProtocol,
       X509Certificate certificate =
           scmCertificateServer.getCertificate(certSerialId);
       if (certificate != null) {
-        return CertificateCodec.getPEMEncodedString(certificate);
+        return getPEMEncodedString(certificate);
       }
     } catch (CertificateException e) {
       throw new SCMSecurityException("getCertificate operation failed. ", e,
@@ -359,7 +371,7 @@ public class SCMSecurityProtocolServer implements 
SCMSecurityProtocol,
   public String getCACertificate() throws IOException {
     LOGGER.debug("Getting CA certificate.");
     try {
-      return CertificateCodec.getPEMEncodedString(
+      return getPEMEncodedString(
           scmCertificateServer.getCaCertPath());
     } catch (CertificateException e) {
       throw new SCMSecurityException("getRootCertificate operation failed. ",
@@ -385,7 +397,7 @@ public class SCMSecurityProtocolServer implements 
SCMSecurityProtocol,
     List<String> results = new ArrayList<>(certificates.size());
     for (X509Certificate cert : certificates) {
       try {
-        String certStr = CertificateCodec.getPEMEncodedString(cert);
+        String certStr = getPEMEncodedString(cert);
         results.add(certStr);
       } catch (SCMSecurityException e) {
         throw new SCMSecurityException("listCertificate operation failed.",
@@ -403,13 +415,27 @@ public class SCMSecurityProtocolServer implements 
SCMSecurityProtocol,
   }
 
   @Override
-  public String getRootCACertificate() throws IOException {
+  public synchronized String getRootCACertificate() throws IOException {
     LOGGER.debug("Getting Root CA certificate.");
+    X509Certificate lastExpiringRootCa = null;
     if (storageContainerManager.getScmStorageConfig()
         .checkPrimarySCMIdInitialized()) {
-      return CertificateCodec.getPEMEncodedString(rootCACertificate);
+      Date lastCertDate = new Date(0);
+      for (X509Certificate cert : rootCACertificateList) {
+        if (cert.getNotAfter().after(lastCertDate)) {
+          lastCertDate = cert.getNotAfter();
+          lastExpiringRootCa = cert;
+        }
+      }
+    }
+    if (lastExpiringRootCa == null) {
+      return null;
     }
-    return null;
+    return CertificateCodec.getPEMEncodedString(lastExpiringRootCa);
+  }
+
+  public synchronized void addNewRootCa(X509Certificate rootCaCertToAdd) {
+    rootCACertificateList.add(rootCaCertToAdd);
   }
 
   @Override
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 fac7f0711c..2a791171a7 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
@@ -27,6 +27,7 @@ import com.google.protobuf.BlockingService;
 
 import java.time.Duration;
 import java.util.concurrent.atomic.AtomicBoolean;
+
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hdds.HddsConfigKeys;
@@ -882,14 +883,22 @@ public final class StorageContainerManager extends 
ServiceRuntimeInfoImpl
     SecretKeyManager secretKeyManager = secretKeyManagerService != null ?
         secretKeyManagerService.getSecretKeyManager() : null;
 
+    X509Certificate rootCaCert = scmCertificateClient == null ? null :
+        scmCertificateClient.getRootCACertificate() != null ?
+            scmCertificateClient.getRootCACertificate() :
+            scmCertificateClient.getCACertificate();
+    List<X509Certificate> rootCaList = new ArrayList<>();
+    if (rootCaCert != null) {
+      rootCaList.add(rootCaCert);
+    }
     // We need to pass getCACertificate as rootCA certificate,
     // as for SCM CA is root-CA.
     securityProtocolServer = new SCMSecurityProtocolServer(conf,
-        rootCertificateServer, scmCertificateServer,
-        scmCertificateClient == null ? null :
-            scmCertificateClient.getRootCACertificate() != null ?
-            scmCertificateClient.getRootCACertificate() :
-            scmCertificateClient.getCACertificate(), this, secretKeyManager);
+        rootCertificateServer,
+        scmCertificateServer,
+        rootCaList,
+        this,
+        secretKeyManager);
 
     if (securityConfig.isContainerTokenEnabled()) {
       containerTokenMgr = createContainerTokenSecretManager(configuration);
diff --git 
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/server/TestSCMSecurityProtocolServer.java
 
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/server/TestSCMSecurityProtocolServer.java
index 82f2cc182a..7803025d9d 100644
--- 
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/server/TestSCMSecurityProtocolServer.java
+++ 
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/server/TestSCMSecurityProtocolServer.java
@@ -20,28 +20,42 @@ import static 
org.apache.hadoop.hdds.scm.ScmConfigKeys.OZONE_SCM_SECURITY_SERVIC
 import static 
org.apache.hadoop.hdds.scm.ScmConfigKeys.OZONE_SCM_SECURITY_SERVICE_BIND_HOST_DEFAULT;
 
 import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.hdds.security.x509.certificate.utils.CertificateCodec;
+import org.apache.hadoop.security.ssl.KeyStoreTestUtil;
 import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.Timeout;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
 
 import java.io.IOException;
+import java.security.KeyPair;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
 
 /**
  * Test class for {@link SCMSecurityProtocolServer}.
- * */
+ */
 @Timeout(20)
 public class TestSCMSecurityProtocolServer {
   private SCMSecurityProtocolServer securityProtocolServer;
   private OzoneConfiguration config;
+  @Mock
+  private StorageContainerManager mockScm;
+  @Mock
+  private SCMStorageConfig storageConfigMock;
 
   @BeforeEach
   public void setUp() throws Exception {
+    MockitoAnnotations.openMocks(this);
     config = new OzoneConfiguration();
     config.set(OZONE_SCM_SECURITY_SERVICE_ADDRESS_KEY,
         OZONE_SCM_SECURITY_SERVICE_BIND_HOST_DEFAULT + ":0");
     securityProtocolServer = new SCMSecurityProtocolServer(config, null,
-        null, null, null, null);
+        null, new ArrayList<>(), mockScm, null);
   }
 
   @AfterEach
@@ -62,4 +76,24 @@ public class TestSCMSecurityProtocolServer {
   public void testStop() {
     securityProtocolServer.stop();
   }
+
+  @Test
+  public void testReturnLastRootCa() throws Exception {
+    KeyPair keyPair = KeyStoreTestUtil.generateKeyPair("RSA");
+    X509Certificate oldRootCa = KeyStoreTestUtil.generateCertificate("CN=dn",
+        keyPair, 15, "SHA256withRSA");
+    X509Certificate latestRootCa = 
KeyStoreTestUtil.generateCertificate("CN=dn",
+        keyPair, 30, "SHA256withRSA");
+    Assertions.assertTrue(oldRootCa.getNotAfter().toInstant()
+        .isBefore(latestRootCa.getNotAfter().toInstant()));
+    securityProtocolServer.addNewRootCa(oldRootCa);
+    securityProtocolServer.addNewRootCa(latestRootCa);
+    String pemEncodedLatestRootCa =
+        CertificateCodec.getPEMEncodedString(latestRootCa);
+    Mockito.when(mockScm.getScmStorageConfig()).thenReturn(storageConfigMock);
+    Mockito.when(
+        storageConfigMock.checkPrimarySCMIdInitialized()).thenReturn(true);
+    Assertions.assertEquals(securityProtocolServer.getRootCACertificate(),
+        pemEncodedLatestRootCa);
+  }
 }


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

Reply via email to