Skip to content

Commit 4a3cdde

Browse files
Ajay Kumarxiaoyuyao
authored andcommitted
HDDS-134. SCM CA: OM sends CSR and uses certificate issued by SCM. Contributed by Ajay Kumar.
1 parent 8b72aea commit 4a3cdde

File tree

20 files changed

+739
-100
lines changed

20 files changed

+739
-100
lines changed

hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/client/CertificateClient.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ boolean verifySignature(byte[] data, byte[] signature,
109109
*
110110
* @return CertificateSignRequest.Builder
111111
*/
112-
CertificateSignRequest.Builder getCSRBuilder();
112+
CertificateSignRequest.Builder getCSRBuilder() throws CertificateException;
113113

114114
/**
115115
* Get the certificate of well-known entity from SCM.

hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/client/DNCertificateClient.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

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

22+
import org.apache.hadoop.hdds.security.x509.certificates.utils.CertificateSignRequest;
23+
import org.apache.hadoop.hdds.security.x509.exceptions.CertificateException;
2224
import org.slf4j.Logger;
2325
import org.slf4j.LoggerFactory;
2426

@@ -30,8 +32,22 @@ public class DNCertificateClient extends DefaultCertificateClient {
3032

3133
private static final Logger LOG =
3234
LoggerFactory.getLogger(DNCertificateClient.class);
33-
DNCertificateClient(SecurityConfig securityConfig, String component) {
34-
super(securityConfig, component, LOG);
35+
public DNCertificateClient(SecurityConfig securityConfig) {
36+
super(securityConfig, LOG);
37+
}
38+
39+
/**
40+
* Returns a CSR builder that can be used to creates a Certificate signing
41+
* request.
42+
*
43+
* @return CertificateSignRequest.Builder
44+
*/
45+
@Override
46+
public CertificateSignRequest.Builder getCSRBuilder()
47+
throws CertificateException {
48+
return super.getCSRBuilder()
49+
.setDigitalEncryption(false)
50+
.setDigitalSignature(false);
3551
}
3652

3753
public Logger getLogger() {

hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/client/DefaultCertificateClient.java

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import com.google.common.base.Preconditions;
2323
import org.apache.commons.lang3.RandomStringUtils;
24+
import org.apache.commons.validator.routines.DomainValidator;
2425
import org.apache.hadoop.hdds.security.x509.SecurityConfig;
2526
import org.apache.hadoop.hdds.security.x509.certificate.utils.CertificateCodec;
2627
import org.apache.hadoop.hdds.security.x509.certificates.utils.CertificateSignRequest;
@@ -66,20 +67,16 @@ public abstract class DefaultCertificateClient implements CertificateClient {
6667

6768
private final Logger logger;
6869
private final SecurityConfig securityConfig;
69-
private final String component;
7070
private final KeyCodec keyCodec;
7171
private PrivateKey privateKey;
7272
private PublicKey publicKey;
7373
private X509Certificate x509Certificate;
7474

7575

76-
DefaultCertificateClient(SecurityConfig securityConfig, String component,
77-
Logger log) {
76+
DefaultCertificateClient(SecurityConfig securityConfig, Logger log) {
7877
Objects.requireNonNull(securityConfig);
79-
Objects.requireNonNull(component);
80-
this.component = component;
8178
this.securityConfig = securityConfig;
82-
keyCodec = new KeyCodec(securityConfig, component);
79+
keyCodec = new KeyCodec(securityConfig);
8380
this.logger = log;
8481
}
8582

@@ -95,15 +92,14 @@ public PrivateKey getPrivateKey() {
9592
return privateKey;
9693
}
9794

98-
Path keyPath = securityConfig.getKeyLocation(component);
95+
Path keyPath = securityConfig.getKeyLocation();
9996
if (OzoneSecurityUtil.checkIfFileExist(keyPath,
10097
securityConfig.getPrivateKeyFileName())) {
10198
try {
10299
privateKey = keyCodec.readPrivateKey();
103100
} catch (InvalidKeySpecException | NoSuchAlgorithmException
104101
| IOException e) {
105-
getLogger().error("Error while getting private key for {}",
106-
component, e);
102+
getLogger().error("Error while getting private key.", e);
107103
}
108104
}
109105
return privateKey;
@@ -121,15 +117,14 @@ public PublicKey getPublicKey() {
121117
return publicKey;
122118
}
123119

124-
Path keyPath = securityConfig.getKeyLocation(component);
120+
Path keyPath = securityConfig.getKeyLocation();
125121
if (OzoneSecurityUtil.checkIfFileExist(keyPath,
126122
securityConfig.getPublicKeyFileName())) {
127123
try {
128124
publicKey = keyCodec.readPublicKey();
129125
} catch (InvalidKeySpecException | NoSuchAlgorithmException
130126
| IOException e) {
131-
getLogger().error("Error while getting private key for {}",
132-
component, e);
127+
getLogger().error("Error while getting public key.", e);
133128
}
134129
}
135130
return publicKey;
@@ -147,18 +142,18 @@ public X509Certificate getCertificate() {
147142
return x509Certificate;
148143
}
149144

150-
Path certPath = securityConfig.getCertificateLocation(component);
145+
Path certPath = securityConfig.getCertificateLocation();
151146
if (OzoneSecurityUtil.checkIfFileExist(certPath,
152147
securityConfig.getCertificateFileName())) {
153148
CertificateCodec certificateCodec =
154-
new CertificateCodec(securityConfig, component);
149+
new CertificateCodec(securityConfig);
155150
try {
156151
X509CertificateHolder x509CertificateHolder =
157152
certificateCodec.readCertificate();
158153
x509Certificate =
159154
CertificateCodec.getX509Certificate(x509CertificateHolder);
160155
} catch (java.security.cert.CertificateException | IOException e) {
161-
getLogger().error("Error reading certificate for {}", component, e);
156+
getLogger().error("Error reading certificate.", e);
162157
}
163158
}
164159
return x509Certificate;
@@ -318,8 +313,26 @@ private boolean verifySignature(byte[] data, byte[] signature,
318313
* @return CertificateSignRequest.Builder
319314
*/
320315
@Override
321-
public CertificateSignRequest.Builder getCSRBuilder() {
322-
return new CertificateSignRequest.Builder();
316+
public CertificateSignRequest.Builder getCSRBuilder()
317+
throws CertificateException {
318+
CertificateSignRequest.Builder builder =
319+
new CertificateSignRequest.Builder()
320+
.setConfiguration(securityConfig.getConfiguration());
321+
try {
322+
DomainValidator validator = DomainValidator.getInstance();
323+
// Add all valid ips.
324+
OzoneSecurityUtil.getValidInetsForCurrentHost().forEach(
325+
ip -> {
326+
builder.addIpAddress(ip.getHostAddress());
327+
if(validator.isValid(ip.getCanonicalHostName())) {
328+
builder.addDnsName(ip.getCanonicalHostName());
329+
}
330+
});
331+
} catch (IOException e) {
332+
throw new CertificateException("Error while adding ip to CSR builder",
333+
e, CSR_ERROR);
334+
}
335+
return builder;
323336
}
324337

325338
/**
@@ -345,8 +358,7 @@ public X509Certificate queryCertificate(String query) {
345358
@Override
346359
public void storeCertificate(X509Certificate certificate)
347360
throws CertificateException {
348-
CertificateCodec certificateCodec = new CertificateCodec(securityConfig,
349-
component);
361+
CertificateCodec certificateCodec = new CertificateCodec(securityConfig);
350362
try {
351363
certificateCodec.writeCertificate(
352364
new X509CertificateHolder(certificate.getEncoded()));
@@ -595,7 +607,7 @@ protected boolean validateKeyPair(PublicKey pubKey)
595607
* location.
596608
* */
597609
protected void bootstrapClientKeys() throws CertificateException {
598-
Path keyPath = securityConfig.getKeyLocation(component);
610+
Path keyPath = securityConfig.getKeyLocation();
599611
if (Files.notExists(keyPath)) {
600612
try {
601613
Files.createDirectories(keyPath);
@@ -618,10 +630,9 @@ protected KeyPair createKeyPair() throws CertificateException {
618630
keyCodec.writePrivateKey(keyPair.getPrivate());
619631
} catch (NoSuchProviderException | NoSuchAlgorithmException
620632
| IOException e) {
621-
getLogger().error("Error while bootstrapping certificate client for {}",
622-
component, e);
623-
throw new CertificateException("Error while bootstrapping certificate " +
624-
"client for" + component, BOOTSTRAP_ERROR);
633+
getLogger().error("Error while bootstrapping certificate client.", e);
634+
throw new CertificateException("Error while bootstrapping certificate.",
635+
BOOTSTRAP_ERROR);
625636
}
626637
return keyPair;
627638
}

hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/client/OMCertificateClient.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

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

22+
import org.apache.hadoop.hdds.security.x509.certificates.utils.CertificateSignRequest;
2223
import org.slf4j.Logger;
2324
import org.slf4j.LoggerFactory;
2425

@@ -38,8 +39,8 @@ public class OMCertificateClient extends DefaultCertificateClient {
3839
private static final Logger LOG =
3940
LoggerFactory.getLogger(OMCertificateClient.class);
4041

41-
public OMCertificateClient(SecurityConfig securityConfig, String component) {
42-
super(securityConfig, component, LOG);
42+
public OMCertificateClient(SecurityConfig securityConfig) {
43+
super(securityConfig, LOG);
4344
}
4445

4546
protected InitResponse handleCase(InitCase init) throws
@@ -96,6 +97,21 @@ protected InitResponse handleCase(InitCase init) throws
9697
}
9798
}
9899

100+
/**
101+
* Returns a CSR builder that can be used to creates a Certificate signing
102+
* request.
103+
*
104+
* @return CertificateSignRequest.Builder
105+
*/
106+
@Override
107+
public CertificateSignRequest.Builder getCSRBuilder()
108+
throws CertificateException {
109+
return super.getCSRBuilder()
110+
.setDigitalEncryption(true)
111+
.setDigitalSignature(true);
112+
}
113+
114+
99115
public Logger getLogger() {
100116
return LOG;
101117
}

hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/certificate/utils/CertificateCodec.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,16 @@ public CertificateCodec(SecurityConfig config, String component) {
8080
this.location = securityConfig.getCertificateLocation(component);
8181
}
8282

83+
/**
84+
* Creates an CertificateCodec.
85+
*
86+
* @param config - Security Config.
87+
*/
88+
public CertificateCodec(SecurityConfig config) {
89+
this.securityConfig = config;
90+
this.location = securityConfig.getCertificateLocation();
91+
}
92+
8393
/**
8494
* Creates an CertificateCodec.
8595
*
@@ -167,6 +177,22 @@ public Path getLocation() {
167177
return location;
168178
}
169179

180+
/**
181+
* Gets the X.509 Certificate from PEM encoded String.
182+
*
183+
* @param pemEncodedString - PEM encoded String.
184+
* @return X509Certificate - Certificate.
185+
* @throws CertificateException - Thrown on Failure.
186+
* @throws IOException - Thrown on Failure.
187+
*/
188+
public static X509Certificate getX509Cert(String pemEncodedString)
189+
throws CertificateException, IOException {
190+
CertificateFactory fact = CertificateFactory.getInstance("X.509");
191+
try (InputStream input = IOUtils.toInputStream(pemEncodedString, UTF_8)) {
192+
return (X509Certificate) fact.generateCertificate(input);
193+
}
194+
}
195+
170196
/**
171197
* Write the Certificate pointed to the location by the configs.
172198
*

hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/certificates/utils/CertificateSignRequest.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ public static class Builder {
144144
private SecurityConfig config;
145145
private List<GeneralName> altNames;
146146
private Boolean ca = false;
147+
private boolean digitalSignature;
148+
private boolean digitalEncryption;
147149

148150
public CertificateSignRequest.Builder setConfiguration(
149151
Configuration configuration) {
@@ -171,6 +173,16 @@ public CertificateSignRequest.Builder setScmID(String s) {
171173
return this;
172174
}
173175

176+
public Builder setDigitalSignature(boolean dSign) {
177+
this.digitalSignature = dSign;
178+
return this;
179+
}
180+
181+
public Builder setDigitalEncryption(boolean dEncryption) {
182+
this.digitalEncryption = dEncryption;
183+
return this;
184+
}
185+
174186
// Support SAN extenion with DNS and RFC822 Name
175187
// other name type will be added as needed.
176188
public CertificateSignRequest.Builder addDnsName(String dnsName) {
@@ -200,8 +212,13 @@ public CertificateSignRequest.Builder setCA(Boolean isCA) {
200212
}
201213

202214
private Extension getKeyUsageExtension() throws IOException {
203-
int keyUsageFlag = KeyUsage.digitalSignature | KeyUsage.keyEncipherment
204-
| KeyUsage.dataEncipherment | KeyUsage.keyAgreement;
215+
int keyUsageFlag = KeyUsage.keyAgreement;
216+
if(digitalEncryption){
217+
keyUsageFlag |= KeyUsage.keyEncipherment | KeyUsage.dataEncipherment;
218+
}
219+
if(digitalSignature) {
220+
keyUsageFlag |= KeyUsage.digitalSignature;
221+
}
205222

206223
if (ca) {
207224
keyUsageFlag |= KeyUsage.keyCertSign | KeyUsage.cRLSign;

hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/exceptions/CertificateException.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ public enum ErrorCode {
8282
CRYPTO_SIGN_ERROR,
8383
CERTIFICATE_ERROR,
8484
BOOTSTRAP_ERROR,
85+
CSR_ERROR,
8586
CRYPTO_SIGNATURE_VERIFICATION_ERROR
8687
}
8788
}

hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/security/x509/keys/KeyCodec.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,17 @@ public KeyCodec(SecurityConfig config, String component) {
8787
this.location = securityConfig.getKeyLocation(component);
8888
}
8989

90+
/**
91+
* Creates an KeyCodec.
92+
*
93+
* @param config - Security Config.
94+
*/
95+
public KeyCodec(SecurityConfig config) {
96+
this.securityConfig = config;
97+
isPosixFileSystem = KeyCodec::isPosix;
98+
this.location = securityConfig.getKeyLocation();
99+
}
100+
90101
/**
91102
* Creates an HDDS Key Writer.
92103
*

hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@ private OzoneConsts() {
272272
public static final Metadata.Key<String> USER_METADATA_KEY =
273273
Metadata.Key.of(OZONE_USER, ASCII_STRING_MARSHALLER);
274274

275+
public static final String RPC_PORT = "RPC";
276+
275277
// Default OMServiceID for OM Ratis servers to use as RaftGroupId
276278
public static final String OM_SERVICE_ID_DEFAULT = "omServiceIdDefault";
277279

0 commit comments

Comments
 (0)