From b448edb4bcebab159210f0c3ff903f57a9331408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szabolcs=20G=C3=A1l?= Date: Thu, 1 Dec 2022 16:21:29 +0100 Subject: [PATCH 01/10] HDDS-7399 enable reading external root ca cert --- .../apache/hadoop/hdds/HddsConfigKeys.java | 18 ++++ .../hdds/security/x509/SecurityConfig.java | 42 +++++++-- .../authority/DefaultCAServer.java | 86 ++++++++++++++----- .../authority/TestDefaultCAServer.java | 70 ++++++++++++++- 4 files changed, 185 insertions(+), 31 deletions(-) diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java index 945ca91a4088..1567530e65a6 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java @@ -194,6 +194,24 @@ public final class HddsConfigKeys { public static final String HDDS_X509_RENEW_GRACE_DURATION_DEFAULT = "P28D"; + public static final String HDDS_EXTERNAL_ROOT_CA_CERT_PATH = + "hdds.external.root.ca.cert"; + + public static final String HDDS_EXTERNAL_ROOT_CA_CERT_PATH_DEFAULT = + ""; + + public static final String HDDS_EXTERNAL_ROOT_CA_PUBLIC_KEY_PATH = + "hdds.external.root.ca.public.key"; + + public static final String HDDS_EXTERNAL_ROOT_CA_PUBLIC_KEY_PATH_DEFAULT = + ""; + + public static final String HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH = + "hdds.external.root.ca.private.key"; + + public static final String HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH_DEFAULT = + ""; + /** * Do not instantiate. */ diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java index 94401e5e3223..7b7eefb71002 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java @@ -19,6 +19,14 @@ package org.apache.hadoop.hdds.security.x509; +import com.google.common.base.Preconditions; +import org.apache.hadoop.hdds.conf.ConfigurationSource; +import org.apache.hadoop.ozone.OzoneConfigKeys; +import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslProvider; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.nio.file.Path; import java.nio.file.Paths; import java.security.Provider; @@ -26,10 +34,6 @@ import java.time.Duration; import java.util.concurrent.TimeUnit; -import org.apache.hadoop.hdds.conf.ConfigurationSource; -import org.apache.hadoop.ozone.OzoneConfigKeys; - -import com.google.common.base.Preconditions; import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_BLOCK_TOKEN_ENABLED; import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_BLOCK_TOKEN_ENABLED_DEFAULT; import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_CONTAINER_TOKEN_ENABLED; @@ -37,6 +41,11 @@ 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_EXTERNAL_ROOT_CA_CERT_PATH; +import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_CERT_PATH_DEFAULT; +import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH; +import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH_DEFAULT; +import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_PUBLIC_KEY_PATH; 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_PROVIDER; @@ -74,10 +83,6 @@ import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_SECURITY_SSL_TRUSTSTORE_RELOAD_INTERVAL_DEFAULT; import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_SECURITY_ENABLED_DEFAULT; import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_SECURITY_ENABLED_KEY; -import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslProvider; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * A class that deals with all Security related configs in HDDS. @@ -111,6 +116,9 @@ public class SecurityConfig { private boolean grpcTlsUseTestCert; private final long keystoreReloadInterval; private final long truststoreReloadInterval; + private String externalRootCaPublicKeyPath; + private String externalRootCaPrivateKeyPath; + private String externalRootCaCert; /** * Constructs a SecurityConfig. @@ -182,8 +190,12 @@ public SecurityConfig(ConfigurationSource configuration) { "greater than maximum Certificate duration"); } + this.externalRootCaCert = this.configuration.get(HDDS_EXTERNAL_ROOT_CA_CERT_PATH, HDDS_EXTERNAL_ROOT_CA_CERT_PATH_DEFAULT); + this.externalRootCaPublicKeyPath = this.configuration.get(HDDS_EXTERNAL_ROOT_CA_PUBLIC_KEY_PATH, HDDS_EXTERNAL_ROOT_CA_CERT_PATH_DEFAULT); + this.externalRootCaPrivateKeyPath = this.configuration.get(HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH, HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH_DEFAULT); + this.crlName = this.configuration.get(HDDS_X509_CRL_NAME, - HDDS_X509_CRL_NAME_DEFAULT); + HDDS_X509_CRL_NAME_DEFAULT); // First Startup -- if the provider is null, check for the provider. if (SecurityConfig.provider == null) { @@ -399,6 +411,18 @@ public SslProvider getGrpcSslProvider() { HDDS_GRPC_TLS_PROVIDER_DEFAULT)); } + public String getExternalRootCaPrivateKeyPath() { + return externalRootCaPrivateKeyPath; + } + + public String getExternalRootCaPublicKeyPath() { + return externalRootCaPublicKeyPath; + } + + public String getExternalRootCaCert() { + return externalRootCaCert; + } + /** * Return true if using test certificates with authority as localhost. This * should be used only for unit test where certificates are generated by diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java index 454ac6c2f4f4..10eab56d6e39 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java @@ -49,6 +49,8 @@ import java.security.KeyPair; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.security.spec.InvalidKeySpecException; @@ -65,8 +67,8 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; -import static org.apache.hadoop.hdds.security.x509.certificates.utils.CertificateSignRequest.getCertificationRequest; import static org.apache.hadoop.hdds.security.exception.SCMSecurityException.ErrorCode.UNABLE_TO_ISSUE_CERTIFICATE; +import static org.apache.hadoop.hdds.security.x509.certificates.utils.CertificateSignRequest.getCertificationRequest; import static org.apache.hadoop.hdds.security.x509.exceptions.CertificateException.ErrorCode.CSR_ERROR; /** @@ -252,7 +254,6 @@ public Future requestCertificate( LOG.error("Certificate storage failed, retrying one more time.", e); xcert = signAndStoreCertificate(beginDate, endDate, csr, role); } - xcertHolder.complete(xcert); break; default: @@ -474,19 +475,7 @@ Consumer processVerificationStatus( break; case INITIALIZE: if (type == CAType.SELF_SIGNED_CA) { - consumer = (arg) -> { - try { - generateSelfSignedCA(arg); - } catch (NoSuchProviderException | NoSuchAlgorithmException - | IOException e) { - LOG.error("Unable to initialize CertificateServer.", e); - } - VerificationStatus newStatus = verifySelfSignedCA(arg); - if (newStatus != VerificationStatus.SUCCESS) { - LOG.error("Unable to initialize CertificateServer, failed in " + - "verification."); - } - }; + consumer = this::initRootCa; } else if (type == CAType.INTERMEDIARY_CA) { // For sub CA certificates are generated during bootstrap/init. If // both keys/certs are missing, init/bootstrap is missed to be @@ -499,13 +488,36 @@ Consumer processVerificationStatus( }; } break; - default: - /* Make CheckStyle happy */ - break; + default: + /* Make CheckStyle happy */ + break; } return consumer; } + private void initRootCa(SecurityConfig config) { + if (isExternalCaSpecified(config)) { + initWithExternalRootCa(config); + } else { + try { + generateSelfSignedCA(config); + } catch (NoSuchProviderException | NoSuchAlgorithmException + | IOException e) { + LOG.error("Unable to initialize CertificateServer.", e); + } + } + VerificationStatus newStatus = verifySelfSignedCA(config); + if (newStatus != VerificationStatus.SUCCESS) { + LOG.error("Unable to initialize CertificateServer, failed in " + + "verification."); + } + } + + private boolean isExternalCaSpecified(SecurityConfig conf) { + return !conf.getExternalRootCaCert().isEmpty() && + !conf.getExternalRootCaPrivateKeyPath().isEmpty(); + } + /** * Generates a KeyPair for the Certificate. * @@ -529,12 +541,12 @@ private KeyPair generateKeys(SecurityConfig securityConfig) * Generates a self-signed Root Certificate for CA. * * @param securityConfig - SecurityConfig - * @param key - KeyPair. + * @param key - KeyPair. * @throws IOException - on Error. * @throws SCMSecurityException - on Error. */ private void generateRootCertificate(SecurityConfig securityConfig, - KeyPair key) throws IOException, SCMSecurityException { + KeyPair key) throws IOException, SCMSecurityException { Preconditions.checkNotNull(this.config); LocalDateTime beginDate = LocalDateTime.of(LocalDate.now(), LocalTime.MIDNIGHT); @@ -563,7 +575,7 @@ private void generateRootCertificate(SecurityConfig securityConfig, } catch (IOException e) { throw new org.apache.hadoop.hdds.security.x509 .exceptions.CertificateException( - "Error while adding ip to CA self signed certificate", e, + "Error while adding ip to CA self signed certificate", e, CSR_ERROR); } X509CertificateHolder selfSignedCertificate = builder.build(); @@ -573,6 +585,38 @@ private void generateRootCertificate(SecurityConfig securityConfig, certCodec.writeCertificate(selfSignedCertificate); } + private void initWithExternalRootCa(SecurityConfig conf) { + String externalRootCaLocation = conf.getExternalRootCaCert(); + CertificateCodec certificateCodec = + new CertificateCodec(config, componentName); + KeyCodec keyCodec = new KeyCodec(config, componentName); + Path extCertPath = Paths.get(externalRootCaLocation); + Path extPrivateKeyPath = Paths.get(conf.getExternalRootCaPrivateKeyPath()); + String externalPublicKeyLocation = conf.getExternalRootCaPublicKeyPath(); + + try { + PrivateKey privateKey = keyCodec.readPrivateKey( + extPrivateKeyPath.getParent(), + extPrivateKeyPath.getFileName().toString()); + X509CertificateHolder certHolder = certificateCodec.readCertificate( + extCertPath.getParent(), extCertPath.getFileName().toString()); + PublicKey publicKey; + if (externalPublicKeyLocation.isEmpty()) { + publicKey = CertificateCodec.getX509Certificate(certHolder) + .getPublicKey(); + } else { + Path publicKeyPath = Paths.get(externalPublicKeyLocation); + publicKey = keyCodec.readPublicKey( + publicKeyPath.getParent(), publicKeyPath.getFileName().toString()); + } + keyCodec.writeKey(new KeyPair(publicKey, privateKey)); + certificateCodec.writeCertificate(certHolder); + } catch (IOException | CertificateException | NoSuchAlgorithmException | + InvalidKeySpecException e) { + LOG.error("External root CA certificate initialization failed", e); + } + } + /** * This represents the verification status of the CA. Based on this enum * appropriate action is taken in the Init. diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java index 7c3e035f1c67..332053101e69 100644 --- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java +++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java @@ -20,6 +20,7 @@ package org.apache.hadoop.hdds.security.x509.certificate.authority; import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.validator.routines.DomainValidator; import org.apache.hadoop.hdds.HddsConfigKeys; import org.apache.hadoop.hdds.conf.OzoneConfiguration; import org.apache.hadoop.hdds.security.exception.SCMSecurityException; @@ -29,9 +30,11 @@ import org.apache.hadoop.hdds.security.x509.certificate.client.SCMCertificateClient; import org.apache.hadoop.hdds.security.x509.certificate.utils.CertificateCodec; import org.apache.hadoop.hdds.security.x509.certificates.utils.CertificateSignRequest; +import org.apache.hadoop.hdds.security.x509.certificates.utils.SelfSignedCertificate; import org.apache.hadoop.hdds.security.x509.keys.HDDSKeyGenerator; +import org.apache.hadoop.hdds.security.x509.keys.KeyCodec; +import org.apache.hadoop.ozone.OzoneSecurityUtil; import org.apache.ozone.test.LambdaTestUtils; - import org.bouncycastle.asn1.x509.CRLReason; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; @@ -50,12 +53,14 @@ import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.ZoneId; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Optional; +import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.function.Consumer; @@ -65,6 +70,7 @@ import static org.apache.hadoop.hdds.protocol.proto.HddsProtos.NodeType.SCM; import static org.apache.hadoop.hdds.security.x509.certificate.authority.CertificateServer.CAType.INTERMEDIARY_CA; import static org.apache.hadoop.hdds.security.x509.certificate.authority.CertificateServer.CAType.SELF_SIGNED_CA; +import static org.apache.hadoop.hdds.security.x509.exceptions.CertificateException.ErrorCode.CSR_ERROR; import static org.apache.hadoop.ozone.OzoneConsts.SCM_CA_CERT_STORAGE_DIR; import static org.apache.hadoop.ozone.OzoneConsts.SCM_CA_PATH; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -339,6 +345,27 @@ public void testIntermediaryCAWithEmpty() { () -> scmCA.init(new SecurityConfig(conf), INTERMEDIARY_CA)); } + @Test + public void testExternalRootCA(@TempDir Path tempDir) throws Exception { + String externalCaCert = "CaCert.pem"; + SecurityConfig securityConfig = new SecurityConfig(conf); + SCMCertificateClient scmCertificateClient = + new SCMCertificateClient(new SecurityConfig(conf)); + KeyPair keyPair = new HDDSKeyGenerator(conf).generateKey(); + KeyCodec keyPEMWriter = new KeyCodec(securityConfig, + scmCertificateClient.getComponentName()); + keyPEMWriter.writeKey(tempDir, keyPair, true); + X509CertificateHolder certificateHolder = generateExternalCert(securityConfig); + + CertificateCodec certificateCodec = new CertificateCodec(securityConfig, + scmCertificateClient.getComponentName()); + + certificateCodec.writeCertificate(tempDir, externalCaCert, + CertificateCodec.getPEMEncodedString(certificateHolder), true); + + conf.set(HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_CERT_PATH, tempDir.toString()); + } + @Test public void testIntermediaryCA() throws Exception { @@ -414,4 +441,45 @@ clusterId, scmId, caStore, new DefaultProfile(), } + private X509CertificateHolder generateExternalCert(SecurityConfig securityConfig) throws Exception { + LocalDateTime notBefore = LocalDateTime.now(); + LocalDateTime notAfter = notBefore.plusYears(1); + String clusterID = UUID.randomUUID().toString(); + String scmID = UUID.randomUUID().toString(); + String subject = "testRootCert"; + HDDSKeyGenerator keyGen = + new HDDSKeyGenerator(securityConfig.getConfiguration()); + KeyPair keyPair = keyGen.generateKey(); + + SelfSignedCertificate.Builder builder = + SelfSignedCertificate.newBuilder() + .setBeginDate(notBefore) + .setEndDate(notAfter) + .setClusterID(clusterID) + .setScmID(scmID) + .setSubject(subject) + .setKey(keyPair) + .setConfiguration(conf) + .makeCA(); + + try { + DomainValidator validator = DomainValidator.getInstance(); + // Add all valid ips. + OzoneSecurityUtil.getValidInetsForCurrentHost().forEach( + ip -> { + builder.addIpAddress(ip.getHostAddress()); + if (validator.isValid(ip.getCanonicalHostName())) { + builder.addDnsName(ip.getCanonicalHostName()); + } + }); + } catch (IOException e) { + throw new org.apache.hadoop.hdds.security.x509 + .exceptions.CertificateException( + "Error while adding ip to CA self signed certificate", e, + CSR_ERROR); + } + + return builder.build(); + } + } From 77b6eb745ded97f2701d19fb7dffad138024b81c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szabolcs=20G=C3=A1l?= Date: Tue, 6 Dec 2022 15:21:25 +0100 Subject: [PATCH 02/10] HDDS-7399. Read external CA certificate if specified. --- .../hdds/security/x509/SecurityConfig.java | 12 ++- .../authority/DefaultCAServer.java | 73 ++++++++++++------- .../hdds/security/x509/keys/KeyCodec.java | 4 +- .../authority/TestDefaultCAServer.java | 53 ++++++++++---- 4 files changed, 96 insertions(+), 46 deletions(-) diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java index 7b7eefb71002..d44a472c8fe2 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java @@ -190,9 +190,15 @@ public SecurityConfig(ConfigurationSource configuration) { "greater than maximum Certificate duration"); } - this.externalRootCaCert = this.configuration.get(HDDS_EXTERNAL_ROOT_CA_CERT_PATH, HDDS_EXTERNAL_ROOT_CA_CERT_PATH_DEFAULT); - this.externalRootCaPublicKeyPath = this.configuration.get(HDDS_EXTERNAL_ROOT_CA_PUBLIC_KEY_PATH, HDDS_EXTERNAL_ROOT_CA_CERT_PATH_DEFAULT); - this.externalRootCaPrivateKeyPath = this.configuration.get(HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH, HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH_DEFAULT); + this.externalRootCaCert = this.configuration.get( + HDDS_EXTERNAL_ROOT_CA_CERT_PATH, + HDDS_EXTERNAL_ROOT_CA_CERT_PATH_DEFAULT); + this.externalRootCaPublicKeyPath = this.configuration.get( + HDDS_EXTERNAL_ROOT_CA_PUBLIC_KEY_PATH, + HDDS_EXTERNAL_ROOT_CA_CERT_PATH_DEFAULT); + this.externalRootCaPrivateKeyPath = this.configuration.get( + HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH, + HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH_DEFAULT); this.crlName = this.configuration.get(HDDS_X509_CRL_NAME, HDDS_X509_CRL_NAME_DEFAULT); diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java index 10eab56d6e39..cb9c82f7411e 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java @@ -455,9 +455,11 @@ Consumer processVerificationStatus( break; case MISSING_KEYS: consumer = (arg) -> { - LOG.error("We have found the Certificate for this CertificateServer, " + + LOG.error("We have found the Certificate for this " + + "CertificateServer, " + "but keys used by this CertificateServer is missing. This is a " + - "non-recoverable error. Please restart the system after locating " + + "non-recoverable error. Please restart the system after " + + "locating " + "the Keys used by the CertificateServer."); LOG.error("Exiting due to unrecoverable CertificateServer error."); throw new IllegalStateException("Missing Keys, cannot continue."); @@ -466,11 +468,13 @@ Consumer processVerificationStatus( case MISSING_CERTIFICATE: consumer = (arg) -> { LOG.error("We found the keys, but the root certificate for this " + - "CertificateServer is missing. Please restart SCM after locating " + + "CertificateServer is missing. Please restart SCM after " + + "locating " + "the " + "Certificates."); LOG.error("Exiting due to unrecoverable CertificateServer error."); - throw new IllegalStateException("Missing Root Certs, cannot continue."); + throw new IllegalStateException("Missing Root Certs, cannot " + + "continue."); }; break; case INITIALIZE: @@ -481,32 +485,33 @@ Consumer processVerificationStatus( // both keys/certs are missing, init/bootstrap is missed to be // performed. consumer = (arg) -> { - LOG.error("Sub SCM CA Server is missing keys/certs. SCM is started " + + LOG.error("Sub SCM CA Server is missing keys/certs. SCM is " + + "started " + "with out init/bootstrap"); throw new IllegalStateException("INTERMEDIARY_CA Should not be" + " in Initialize State during startup."); }; } break; - default: - /* Make CheckStyle happy */ - break; + default: + /* Make CheckStyle happy */ + break; } return consumer; } - private void initRootCa(SecurityConfig config) { - if (isExternalCaSpecified(config)) { - initWithExternalRootCa(config); + private void initRootCa(SecurityConfig securityConfig) { + if (isExternalCaSpecified(securityConfig)) { + initWithExternalRootCa(securityConfig); } else { try { - generateSelfSignedCA(config); + generateSelfSignedCA(securityConfig); } catch (NoSuchProviderException | NoSuchAlgorithmException | IOException e) { LOG.error("Unable to initialize CertificateServer.", e); } } - VerificationStatus newStatus = verifySelfSignedCA(config); + VerificationStatus newStatus = verifySelfSignedCA(securityConfig); if (newStatus != VerificationStatus.SUCCESS) { LOG.error("Unable to initialize CertificateServer, failed in " + "verification."); @@ -545,8 +550,9 @@ private KeyPair generateKeys(SecurityConfig securityConfig) * @throws IOException - on Error. * @throws SCMSecurityException - on Error. */ - private void generateRootCertificate(SecurityConfig securityConfig, - KeyPair key) throws IOException, SCMSecurityException { + private void generateRootCertificate( + SecurityConfig securityConfig, KeyPair key) + throws IOException, SCMSecurityException { Preconditions.checkNotNull(this.config); LocalDateTime beginDate = LocalDateTime.of(LocalDate.now(), LocalTime.MIDNIGHT); @@ -587,28 +593,22 @@ private void generateRootCertificate(SecurityConfig securityConfig, private void initWithExternalRootCa(SecurityConfig conf) { String externalRootCaLocation = conf.getExternalRootCaCert(); - CertificateCodec certificateCodec = - new CertificateCodec(config, componentName); - KeyCodec keyCodec = new KeyCodec(config, componentName); Path extCertPath = Paths.get(externalRootCaLocation); Path extPrivateKeyPath = Paths.get(conf.getExternalRootCaPrivateKeyPath()); String externalPublicKeyLocation = conf.getExternalRootCaPublicKeyPath(); + KeyCodec keyCodec = new KeyCodec(config, componentName); + CertificateCodec certificateCodec = + new CertificateCodec(config, componentName); try { + X509CertificateHolder certHolder = certificateCodec.readCertificate( + extCertPath.getParent(), extCertPath.getFileName().toString()); PrivateKey privateKey = keyCodec.readPrivateKey( extPrivateKeyPath.getParent(), extPrivateKeyPath.getFileName().toString()); - X509CertificateHolder certHolder = certificateCodec.readCertificate( - extCertPath.getParent(), extCertPath.getFileName().toString()); PublicKey publicKey; - if (externalPublicKeyLocation.isEmpty()) { - publicKey = CertificateCodec.getX509Certificate(certHolder) - .getPublicKey(); - } else { - Path publicKeyPath = Paths.get(externalPublicKeyLocation); - publicKey = keyCodec.readPublicKey( - publicKeyPath.getParent(), publicKeyPath.getFileName().toString()); - } + publicKey = readPublicKeyWithExternalData( + externalPublicKeyLocation, keyCodec, certHolder); keyCodec.writeKey(new KeyPair(publicKey, privateKey)); certificateCodec.writeCertificate(certHolder); } catch (IOException | CertificateException | NoSuchAlgorithmException | @@ -617,6 +617,23 @@ private void initWithExternalRootCa(SecurityConfig conf) { } } + private PublicKey readPublicKeyWithExternalData( + String externalPublicKeyLocation, KeyCodec keyCodec, + X509CertificateHolder certHolder) + throws CertificateException, NoSuchAlgorithmException, + InvalidKeySpecException, IOException { + PublicKey publicKey; + if (externalPublicKeyLocation.isEmpty()) { + publicKey = CertificateCodec.getX509Certificate(certHolder) + .getPublicKey(); + } else { + Path publicKeyPath = Paths.get(externalPublicKeyLocation); + publicKey = keyCodec.readPublicKey( + publicKeyPath.getParent(), publicKeyPath.getFileName().toString()); + } + return publicKey; + } + /** * This represents the verification status of the CA. Based on this enum * appropriate action is taken in the Init. diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/keys/KeyCodec.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/keys/KeyCodec.java index e57510c9ffa1..aead3582249e 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/keys/KeyCodec.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/keys/KeyCodec.java @@ -323,9 +323,9 @@ private synchronized void writeKey(Path basePath, KeyPair keyPair, checkPreconditions(basePath); File privateKeyFile = - Paths.get(location.toString(), privateKeyFileName).toFile(); + Paths.get(basePath.toString(), privateKeyFileName).toFile(); File publicKeyFile = - Paths.get(location.toString(), publicKeyFileName).toFile(); + Paths.get(basePath.toString(), publicKeyFileName).toFile(); checkKeyFile(privateKeyFile, force, publicKeyFile); try (PemWriter privateKeyWriter = new PemWriter(new diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java index 332053101e69..c5a6b6b448e2 100644 --- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java +++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java @@ -34,6 +34,7 @@ import org.apache.hadoop.hdds.security.x509.keys.HDDSKeyGenerator; import org.apache.hadoop.hdds.security.x509.keys.KeyCodec; import org.apache.hadoop.ozone.OzoneSecurityUtil; +import org.apache.hadoop.security.ssl.KeyStoreTestUtil; import org.apache.ozone.test.LambdaTestUtils; import org.bouncycastle.asn1.x509.CRLReason; import org.bouncycastle.cert.X509CertificateHolder; @@ -347,23 +348,53 @@ public void testIntermediaryCAWithEmpty() { @Test public void testExternalRootCA(@TempDir Path tempDir) throws Exception { - String externalCaCert = "CaCert.pem"; + //Given an external certificate + String externalCaCertFileName = "CaCert.pem"; + setExternalPathsInConfig(tempDir, externalCaCertFileName); + SecurityConfig securityConfig = new SecurityConfig(conf); SCMCertificateClient scmCertificateClient = new SCMCertificateClient(new SecurityConfig(conf)); - KeyPair keyPair = new HDDSKeyGenerator(conf).generateKey(); + + KeyPair keyPair = KeyStoreTestUtil.generateKeyPair("RSA"); KeyCodec keyPEMWriter = new KeyCodec(securityConfig, scmCertificateClient.getComponentName()); + keyPEMWriter.writeKey(tempDir, keyPair, true); - X509CertificateHolder certificateHolder = generateExternalCert(securityConfig); + X509CertificateHolder externalCert = generateExternalCert(keyPair); CertificateCodec certificateCodec = new CertificateCodec(securityConfig, scmCertificateClient.getComponentName()); - certificateCodec.writeCertificate(tempDir, externalCaCert, - CertificateCodec.getPEMEncodedString(certificateHolder), true); - - conf.set(HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_CERT_PATH, tempDir.toString()); + certificateCodec.writeCertificate(tempDir, externalCaCertFileName, + CertificateCodec.getPEMEncodedString(externalCert), true); + + CertificateServer testCA = new DefaultCAServer("testCA", + RandomStringUtils.randomAlphabetic(4), + RandomStringUtils.randomAlphabetic(4), caStore, + new DefaultProfile(), + Paths.get(SCM_CA_CERT_STORAGE_DIR, SCM_CA_PATH).toString()); + //When initializing a CA server with external cert + testCA.init(securityConfig, SELF_SIGNED_CA); + //Then the external cert is set as CA cert for the server. + assertEquals(externalCert, testCA.getCACertificate()); + } + + private void setExternalPathsInConfig(Path tempDir, + String externalCaCertFileName) { + String externalCaCertPart = Paths.get(tempDir.toString(), + externalCaCertFileName).toString(); + String privateKeyPath = Paths.get(tempDir.toString(), + HddsConfigKeys.HDDS_PRIVATE_KEY_FILE_NAME_DEFAULT).toString(); + String publicKeyPath = Paths.get(tempDir.toString(), + HddsConfigKeys.HDDS_PUBLIC_KEY_FILE_NAME_DEFAULT).toString(); + + conf.set(HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_CERT_PATH, + externalCaCertPart); + conf.set(HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH, + privateKeyPath); + conf.set(HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_PUBLIC_KEY_PATH, + publicKeyPath); } @Test @@ -441,15 +472,13 @@ clusterId, scmId, caStore, new DefaultProfile(), } - private X509CertificateHolder generateExternalCert(SecurityConfig securityConfig) throws Exception { + private X509CertificateHolder generateExternalCert(KeyPair keyPair) + throws Exception { LocalDateTime notBefore = LocalDateTime.now(); LocalDateTime notAfter = notBefore.plusYears(1); String clusterID = UUID.randomUUID().toString(); String scmID = UUID.randomUUID().toString(); String subject = "testRootCert"; - HDDSKeyGenerator keyGen = - new HDDSKeyGenerator(securityConfig.getConfiguration()); - KeyPair keyPair = keyGen.generateKey(); SelfSignedCertificate.Builder builder = SelfSignedCertificate.newBuilder() @@ -478,8 +507,6 @@ private X509CertificateHolder generateExternalCert(SecurityConfig securityConfig "Error while adding ip to CA self signed certificate", e, CSR_ERROR); } - return builder.build(); } - } From 404fed3b72e1ff5ab25e00cb830f0dfb304854da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szabolcs=20G=C3=A1l?= Date: Wed, 7 Dec 2022 09:53:52 +0100 Subject: [PATCH 03/10] HDDS-7399. Rebase to current changes in master --- .../x509/certificate/authority/DefaultCAServer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java index cb9c82f7411e..4b727cae1b56 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java @@ -493,9 +493,9 @@ Consumer processVerificationStatus( }; } break; - default: - /* Make CheckStyle happy */ - break; + default: + /* Make CheckStyle happy */ + break; } return consumer; } From b0e8139584f7aa2e0cb9e3ef25fa8b44b5c547f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szabolcs=20G=C3=A1l?= Date: Tue, 6 Dec 2022 15:21:25 +0100 Subject: [PATCH 04/10] HDDS-7399. Rebase to current version --- .../x509/certificate/authority/DefaultCAServer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java index 4b727cae1b56..cb9c82f7411e 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java @@ -493,9 +493,9 @@ Consumer processVerificationStatus( }; } break; - default: - /* Make CheckStyle happy */ - break; + default: + /* Make CheckStyle happy */ + break; } return consumer; } From 31cc69ef541b073d07e1458f0d6335cf14a3165c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szabolcs=20G=C3=A1l?= Date: Wed, 7 Dec 2022 10:11:37 +0100 Subject: [PATCH 05/10] HDDS-7399. Fix warning messages regarding final fields --- .../apache/hadoop/hdds/security/x509/SecurityConfig.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java index d44a472c8fe2..279da45577c1 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java @@ -116,9 +116,9 @@ public class SecurityConfig { private boolean grpcTlsUseTestCert; private final long keystoreReloadInterval; private final long truststoreReloadInterval; - private String externalRootCaPublicKeyPath; - private String externalRootCaPrivateKeyPath; - private String externalRootCaCert; + private final String externalRootCaPublicKeyPath; + private final String externalRootCaPrivateKeyPath; + private final String externalRootCaCert; /** * Constructs a SecurityConfig. From 0f304b4ad336fcd5bded16889e1067cdd93d80aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szabolcs=20G=C3=A1l?= Date: Wed, 7 Dec 2022 10:25:13 +0100 Subject: [PATCH 06/10] HDDS-7399. Fix whitespace and import changes --- .../hdds/security/x509/SecurityConfig.java | 18 ++++++++++-------- .../certificate/authority/DefaultCAServer.java | 17 ++++++----------- .../authority/TestDefaultCAServer.java | 1 + 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java index 279da45577c1..3538e0c5833e 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java @@ -19,14 +19,6 @@ package org.apache.hadoop.hdds.security.x509; -import com.google.common.base.Preconditions; -import org.apache.hadoop.hdds.conf.ConfigurationSource; -import org.apache.hadoop.ozone.OzoneConfigKeys; -import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslProvider; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.nio.file.Path; import java.nio.file.Paths; import java.security.Provider; @@ -34,6 +26,11 @@ import java.time.Duration; import java.util.concurrent.TimeUnit; +import org.apache.hadoop.hdds.conf.ConfigurationSource; +import org.apache.hadoop.ozone.OzoneConfigKeys; + +import com.google.common.base.Preconditions; + import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_BLOCK_TOKEN_ENABLED; import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_BLOCK_TOKEN_ENABLED_DEFAULT; import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_CONTAINER_TOKEN_ENABLED; @@ -84,6 +81,11 @@ import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_SECURITY_ENABLED_DEFAULT; import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_SECURITY_ENABLED_KEY; +import org.apache.ratis.thirdparty.io.netty.handler.ssl.SslProvider; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * A class that deals with all Security related configs in HDDS. *

diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java index cb9c82f7411e..715fce94207f 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java @@ -67,8 +67,8 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; -import static org.apache.hadoop.hdds.security.exception.SCMSecurityException.ErrorCode.UNABLE_TO_ISSUE_CERTIFICATE; import static org.apache.hadoop.hdds.security.x509.certificates.utils.CertificateSignRequest.getCertificationRequest; +import static org.apache.hadoop.hdds.security.exception.SCMSecurityException.ErrorCode.UNABLE_TO_ISSUE_CERTIFICATE; import static org.apache.hadoop.hdds.security.x509.exceptions.CertificateException.ErrorCode.CSR_ERROR; /** @@ -455,11 +455,9 @@ Consumer processVerificationStatus( break; case MISSING_KEYS: consumer = (arg) -> { - LOG.error("We have found the Certificate for this " + - "CertificateServer, " + + LOG.error("We have found the Certificate for this CertificateServer, " + "but keys used by this CertificateServer is missing. This is a " + - "non-recoverable error. Please restart the system after " + - "locating " + + "non-recoverable error. Please restart the system after locating " + "the Keys used by the CertificateServer."); LOG.error("Exiting due to unrecoverable CertificateServer error."); throw new IllegalStateException("Missing Keys, cannot continue."); @@ -468,13 +466,11 @@ Consumer processVerificationStatus( case MISSING_CERTIFICATE: consumer = (arg) -> { LOG.error("We found the keys, but the root certificate for this " + - "CertificateServer is missing. Please restart SCM after " + - "locating " + + "CertificateServer is missing. Please restart SCM after locating " + "the " + "Certificates."); LOG.error("Exiting due to unrecoverable CertificateServer error."); - throw new IllegalStateException("Missing Root Certs, cannot " + - "continue."); + throw new IllegalStateException("Missing Root Certs, cannot continue."); }; break; case INITIALIZE: @@ -485,8 +481,7 @@ Consumer processVerificationStatus( // both keys/certs are missing, init/bootstrap is missed to be // performed. consumer = (arg) -> { - LOG.error("Sub SCM CA Server is missing keys/certs. SCM is " + - "started " + + LOG.error("Sub SCM CA Server is missing keys/certs. SCM is started " + "with out init/bootstrap"); throw new IllegalStateException("INTERMEDIARY_CA Should not be" + " in Initialize State during startup."); diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java index c5a6b6b448e2..4a38448b4102 100644 --- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java +++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java @@ -36,6 +36,7 @@ import org.apache.hadoop.ozone.OzoneSecurityUtil; import org.apache.hadoop.security.ssl.KeyStoreTestUtil; import org.apache.ozone.test.LambdaTestUtils; + import org.bouncycastle.asn1.x509.CRLReason; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; From 3490c0e2c3a05643fc5cf8a7d08481c49de7b311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szabolcs=20G=C3=A1l?= Date: Wed, 7 Dec 2022 16:11:21 +0100 Subject: [PATCH 07/10] HDDS-7399. Resolve findbugs issues and test failures. --- .../authority/DefaultCAServer.java | 26 +++++++++++++++---- .../authority/TestDefaultCAServer.java | 3 ++- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java index 715fce94207f..5abd72cabc0c 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/authority/DefaultCAServer.java @@ -596,11 +596,22 @@ private void initWithExternalRootCa(SecurityConfig conf) { CertificateCodec certificateCodec = new CertificateCodec(config, componentName); try { + Path extCertParent = extCertPath.getParent(); + Path extCertName = extCertPath.getFileName(); + if (extCertParent == null || extCertName == null) { + throw new IOException("External cert path is not correct: " + + extCertPath); + } X509CertificateHolder certHolder = certificateCodec.readCertificate( - extCertPath.getParent(), extCertPath.getFileName().toString()); - PrivateKey privateKey = keyCodec.readPrivateKey( - extPrivateKeyPath.getParent(), - extPrivateKeyPath.getFileName().toString()); + extCertParent, extCertName.toString()); + Path extPrivateKeyParent = extPrivateKeyPath.getParent(); + Path extPrivateKeyFileName = extPrivateKeyPath.getFileName(); + if (extPrivateKeyParent == null || extPrivateKeyFileName == null) { + throw new IOException("External private key path is not correct: " + + extPrivateKeyPath); + } + PrivateKey privateKey = keyCodec.readPrivateKey(extPrivateKeyParent, + extPrivateKeyFileName.toString()); PublicKey publicKey; publicKey = readPublicKeyWithExternalData( externalPublicKeyLocation, keyCodec, certHolder); @@ -623,8 +634,13 @@ private PublicKey readPublicKeyWithExternalData( .getPublicKey(); } else { Path publicKeyPath = Paths.get(externalPublicKeyLocation); + Path publicKeyPathFileName = publicKeyPath.getFileName(); + Path publicKeyParent = publicKeyPath.getParent(); + if (publicKeyPathFileName == null || publicKeyParent == null) { + throw new IOException("Public key path incorrect: " + publicKeyParent); + } publicKey = keyCodec.readPublicKey( - publicKeyPath.getParent(), publicKeyPath.getFileName().toString()); + publicKeyParent, publicKeyPathFileName.toString()); } return publicKey; } diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java index 4a38448b4102..08a8eeb50867 100644 --- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java +++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java @@ -85,11 +85,12 @@ * Tests the Default CA Server. */ public class TestDefaultCAServer { - private static OzoneConfiguration conf = new OzoneConfiguration(); + private OzoneConfiguration conf; private MockCAStore caStore; @BeforeEach public void init(@TempDir Path tempDir) throws IOException { + conf = new OzoneConfiguration(); conf.set(OZONE_METADATA_DIRS, tempDir.toString()); caStore = new MockCAStore(); } From 2655a55e25903dca131331f1497b72fb7ba01e8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szabolcs=20G=C3=A1l?= Date: Fri, 9 Dec 2022 10:20:06 +0100 Subject: [PATCH 08/10] HDDS-7399. Add new values to ozone-default.xml --- .../src/main/resources/ozone-default.xml | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/hadoop-hdds/common/src/main/resources/ozone-default.xml b/hadoop-hdds/common/src/main/resources/ozone-default.xml index fe11a3b72e18..e24224643ec1 100644 --- a/hadoop-hdds/common/src/main/resources/ozone-default.xml +++ b/hadoop-hdds/common/src/main/resources/ozone-default.xml @@ -2087,7 +2087,8 @@ Max time for which certificate issued by SCM CA are valid. This duration is used for self-signed root cert and scm sub-ca certs issued by root ca. The formats accepted are based on the ISO-8601 - duration format PnDTnHnMn.nS + duration format PnDTnHnMn.nS + hdds.x509.signature.algorithm @@ -2095,6 +2096,32 @@ OZONE, HDDS, SECURITY X509 signature certificate. + + hdds.external.root.ca.cert + + Path to an external CA certificate. This certificate is + used when initializing SCM to create a root certificate authority. + By default, a self-signed certificate is generated instead. + + + + hdds.external.root.ca.private.key + + Path to an external private key. This private key is later used + when initializing SCM to sign certificates as the root certificate + authority. When not specified a private and public key is generated + instead. + + + + hdds.external.root.ca.public.key + + Path to an external public key. This public key is later used + when initializing SCM to sign certificates as the root certificate + authority. When only the private key is specified + the public key is read from the external certificate. + + ozone.scm.security.handler.count.key 2 From e16093a752f790823ac274fdbed72e0e9d93c3ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szabolcs=20G=C3=A1l?= Date: Thu, 15 Dec 2022 14:34:09 +0100 Subject: [PATCH 09/10] HDDS-7399. Update description of the new fields, fix obvious bug. --- .../apache/hadoop/hdds/HddsConfigKeys.java | 6 ++-- .../hdds/security/x509/SecurityConfig.java | 3 +- .../src/main/resources/ozone-default.xml | 29 ++++++++++++------- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java index 1567530e65a6..70e3b7786a49 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java @@ -195,19 +195,19 @@ public final class HddsConfigKeys { public static final String HDDS_X509_RENEW_GRACE_DURATION_DEFAULT = "P28D"; public static final String HDDS_EXTERNAL_ROOT_CA_CERT_PATH = - "hdds.external.root.ca.cert"; + "hdds.x509.rootca.certificate.file"; public static final String HDDS_EXTERNAL_ROOT_CA_CERT_PATH_DEFAULT = ""; public static final String HDDS_EXTERNAL_ROOT_CA_PUBLIC_KEY_PATH = - "hdds.external.root.ca.public.key"; + "hdds.x509.rootca.public.key.file"; public static final String HDDS_EXTERNAL_ROOT_CA_PUBLIC_KEY_PATH_DEFAULT = ""; public static final String HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH = - "hdds.external.root.ca.private.key"; + "hdds.x509.rootca.private.key.file"; public static final String HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH_DEFAULT = ""; diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java index 3538e0c5833e..05649ac091fb 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java @@ -43,6 +43,7 @@ import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH; import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH_DEFAULT; import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_PUBLIC_KEY_PATH; +import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_PUBLIC_KEY_PATH_DEFAULT; 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_PROVIDER; @@ -197,7 +198,7 @@ public SecurityConfig(ConfigurationSource configuration) { HDDS_EXTERNAL_ROOT_CA_CERT_PATH_DEFAULT); this.externalRootCaPublicKeyPath = this.configuration.get( HDDS_EXTERNAL_ROOT_CA_PUBLIC_KEY_PATH, - HDDS_EXTERNAL_ROOT_CA_CERT_PATH_DEFAULT); + HDDS_EXTERNAL_ROOT_CA_PUBLIC_KEY_PATH_DEFAULT); this.externalRootCaPrivateKeyPath = this.configuration.get( HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH, HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH_DEFAULT); diff --git a/hadoop-hdds/common/src/main/resources/ozone-default.xml b/hadoop-hdds/common/src/main/resources/ozone-default.xml index e24224643ec1..26adf46ecdb5 100644 --- a/hadoop-hdds/common/src/main/resources/ozone-default.xml +++ b/hadoop-hdds/common/src/main/resources/ozone-default.xml @@ -2097,29 +2097,38 @@ X509 signature certificate. - hdds.external.root.ca.cert + hdds.x509.rootca.certificate.file - Path to an external CA certificate. This certificate is - used when initializing SCM to create a root certificate authority. - By default, a self-signed certificate is generated instead. + Path to an external CA certificate. The file format is expected + to be pem. This certificate is used when initializing SCM to create + a root certificate authority. By default, a self-signed certificate is + generated instead. Note that this certificate is only used for Ozone's + internal communication, and it does not affect the certificates used for + HTTPS protocol at WebUIs as they can be configured separately. - hdds.external.root.ca.private.key + hdds.x509.rootca.private.key.file - Path to an external private key. This private key is later used - when initializing SCM to sign certificates as the root certificate - authority. When not specified a private and public key is generated - instead. + Path to an external private key. The file format is expected + to be pem. This private key is later used when initializing SCM to sign + certificates as the root certificate authority. When not specified a + private and public key is generated instead. + These keys are only used for Ozone's internal communication, and it does + not affect the HTTPS protocol at WebUIs as they can be configured + separately. - hdds.external.root.ca.public.key + hdds.x509.rootca.public.key.file Path to an external public key. This public key is later used when initializing SCM to sign certificates as the root certificate authority. When only the private key is specified the public key is read from the external certificate. + Note that this is only used for Ozone's internal communication, and it + does not affect the HTTPS protocol at WebUIs as they can be configured + separately. From 9c8875591f3804a61ec159d302caa4fafb682878 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szabolcs=20G=C3=A1l?= Date: Fri, 16 Dec 2022 08:45:53 +0100 Subject: [PATCH 10/10] HDDS-7399. Update constant names and missing info in public key description --- .../apache/hadoop/hdds/HddsConfigKeys.java | 12 +++++----- .../hdds/security/x509/SecurityConfig.java | 24 +++++++++---------- .../src/main/resources/ozone-default.xml | 14 +++++------ .../authority/TestDefaultCAServer.java | 6 ++--- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java index 70e3b7786a49..bd96f0c26a07 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/HddsConfigKeys.java @@ -194,22 +194,22 @@ public final class HddsConfigKeys { public static final String HDDS_X509_RENEW_GRACE_DURATION_DEFAULT = "P28D"; - public static final String HDDS_EXTERNAL_ROOT_CA_CERT_PATH = + public static final String HDDS_X509_ROOTCA_CERTIFICATE_FILE = "hdds.x509.rootca.certificate.file"; - public static final String HDDS_EXTERNAL_ROOT_CA_CERT_PATH_DEFAULT = + public static final String HDDS_X509_ROOTCA_CERTIFICATE_FILE_DEFAULT = ""; - public static final String HDDS_EXTERNAL_ROOT_CA_PUBLIC_KEY_PATH = + public static final String HDDS_X509_ROOTCA_PUBLIC_KEY_FILE = "hdds.x509.rootca.public.key.file"; - public static final String HDDS_EXTERNAL_ROOT_CA_PUBLIC_KEY_PATH_DEFAULT = + public static final String HDDS_X509_ROOTCA_PUBLIC_KEY_FILE_DEFAULT = ""; - public static final String HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH = + public static final String HDDS_X509_ROOTCA_PRIVATE_KEY_FILE = "hdds.x509.rootca.private.key.file"; - public static final String HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH_DEFAULT = + public static final String HDDS_X509_ROOTCA_PRIVATE_KEY_FILE_DEFAULT = ""; /** diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java index 05649ac091fb..ecc92debdf95 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/SecurityConfig.java @@ -38,12 +38,12 @@ 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_EXTERNAL_ROOT_CA_CERT_PATH; -import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_CERT_PATH_DEFAULT; -import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH; -import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH_DEFAULT; -import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_PUBLIC_KEY_PATH; -import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_PUBLIC_KEY_PATH_DEFAULT; +import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_X509_ROOTCA_CERTIFICATE_FILE; +import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_X509_ROOTCA_CERTIFICATE_FILE_DEFAULT; +import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_X509_ROOTCA_PRIVATE_KEY_FILE; +import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_X509_ROOTCA_PRIVATE_KEY_FILE_DEFAULT; +import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_X509_ROOTCA_PUBLIC_KEY_FILE; +import static org.apache.hadoop.hdds.HddsConfigKeys.HDDS_X509_ROOTCA_PUBLIC_KEY_FILE_DEFAULT; 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_PROVIDER; @@ -194,14 +194,14 @@ public SecurityConfig(ConfigurationSource configuration) { } this.externalRootCaCert = this.configuration.get( - HDDS_EXTERNAL_ROOT_CA_CERT_PATH, - HDDS_EXTERNAL_ROOT_CA_CERT_PATH_DEFAULT); + HDDS_X509_ROOTCA_CERTIFICATE_FILE, + HDDS_X509_ROOTCA_CERTIFICATE_FILE_DEFAULT); this.externalRootCaPublicKeyPath = this.configuration.get( - HDDS_EXTERNAL_ROOT_CA_PUBLIC_KEY_PATH, - HDDS_EXTERNAL_ROOT_CA_PUBLIC_KEY_PATH_DEFAULT); + HDDS_X509_ROOTCA_PUBLIC_KEY_FILE, + HDDS_X509_ROOTCA_PUBLIC_KEY_FILE_DEFAULT); this.externalRootCaPrivateKeyPath = this.configuration.get( - HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH, - HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH_DEFAULT); + HDDS_X509_ROOTCA_PRIVATE_KEY_FILE, + HDDS_X509_ROOTCA_PRIVATE_KEY_FILE_DEFAULT); this.crlName = this.configuration.get(HDDS_X509_CRL_NAME, HDDS_X509_CRL_NAME_DEFAULT); diff --git a/hadoop-hdds/common/src/main/resources/ozone-default.xml b/hadoop-hdds/common/src/main/resources/ozone-default.xml index 26adf46ecdb5..32b446f208d3 100644 --- a/hadoop-hdds/common/src/main/resources/ozone-default.xml +++ b/hadoop-hdds/common/src/main/resources/ozone-default.xml @@ -2122,13 +2122,13 @@ hdds.x509.rootca.public.key.file - Path to an external public key. This public key is later used - when initializing SCM to sign certificates as the root certificate - authority. When only the private key is specified - the public key is read from the external certificate. - Note that this is only used for Ozone's internal communication, and it - does not affect the HTTPS protocol at WebUIs as they can be configured - separately. + Path to an external public key. The file format is expected + to be pem. This public key is later used when initializing SCM to sign + certificates as the root certificate authority. + When only the private key is specified the public key is read from the + external certificate. Note that this is only used for Ozone's internal + communication, and it does not affect the HTTPS protocol at WebUIs as + they can be configured separately. diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java index 08a8eeb50867..b049a6a07655 100644 --- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java +++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/security/x509/certificate/authority/TestDefaultCAServer.java @@ -391,11 +391,11 @@ private void setExternalPathsInConfig(Path tempDir, String publicKeyPath = Paths.get(tempDir.toString(), HddsConfigKeys.HDDS_PUBLIC_KEY_FILE_NAME_DEFAULT).toString(); - conf.set(HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_CERT_PATH, + conf.set(HddsConfigKeys.HDDS_X509_ROOTCA_CERTIFICATE_FILE, externalCaCertPart); - conf.set(HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_PRIVATE_KEY_PATH, + conf.set(HddsConfigKeys.HDDS_X509_ROOTCA_PRIVATE_KEY_FILE, privateKeyPath); - conf.set(HddsConfigKeys.HDDS_EXTERNAL_ROOT_CA_PUBLIC_KEY_PATH, + conf.set(HddsConfigKeys.HDDS_X509_ROOTCA_PUBLIC_KEY_FILE, publicKeyPath); }