Skip to content

Commit c1ba0f2

Browse files
kouzantGautier Berthou
authored andcommitted
[HOPS-1551] System users x.509 v2
1 parent 5dddf6a commit c1ba0f2

File tree

52 files changed

+1309
-569
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1309
-569
lines changed

hadoop-common-project/hadoop-common/src/main/java/io/hops/security/CertificateLocalization.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,6 @@ void updateX509(String username, String applicationId, ByteBuffer keyStore, Stri
6969
String getSuperTruststoreLocation();
7070

7171
String getSuperTruststorePass();
72+
73+
String getSuperMaterialPasswordFile();
7274
}

hadoop-common-project/hadoop-common/src/main/java/io/hops/security/CertificateLocalizationService.java

Lines changed: 29 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@
2525
import org.apache.hadoop.metrics2.util.MBeans;
2626
import org.apache.hadoop.net.HopsSSLSocketFactory;
2727
import org.apache.hadoop.security.ssl.SecurityMaterial;
28-
import org.apache.hadoop.security.ssl.FileBasedKeyStoresFactory;
2928
import org.apache.hadoop.security.ssl.JWTSecurityMaterial;
30-
import org.apache.hadoop.security.ssl.SSLFactory;
3129
import org.apache.hadoop.security.ssl.X509SecurityMaterial;
3230
import org.apache.hadoop.service.AbstractService;
3331
import org.apache.log4j.LogManager;
@@ -64,16 +62,10 @@ public class CertificateLocalizationService extends AbstractService
6462
private final Logger LOG = LogManager.getLogger
6563
(CertificateLocalizationService.class);
6664

67-
private final String SYSTEM_TMP = System.getProperty("java.io.tmpdir",
68-
"/tmp");
65+
private final String SYSTEM_TMP = System.getProperty("java.io.tmpdir", "/tmp");
6966
private final String LOCALIZATION_DIR_NAME = "certLoc";
7067
private Path materializeDir;
71-
private String superKeystoreLocation;
72-
private String superKeystorePass;
73-
private String superKeyPassword;
74-
private String superTrustStoreLocation;
75-
private String superTruststorePass;
76-
68+
7769
private final Map<StorageKey, SecurityMaterial> materialLocation =
7870
new ConcurrentHashMap<>();
7971
private ObjectName mbeanObjectName;
@@ -84,6 +76,8 @@ public class CertificateLocalizationService extends AbstractService
8476
private final BlockingQueue<LocalizationEvent> localizationEventsQ;
8577

8678
private Thread localizationEventsHandler;
79+
private X509SecurityMaterial superuserMaterial;
80+
private char[] keystoresPassword;
8781

8882
@InterfaceAudience.Private
8983
@VisibleForTesting
@@ -118,7 +112,8 @@ public CertificateLocalizationService(ServiceType service) {
118112

119113
@Override
120114
protected void serviceInit(Configuration conf) throws Exception {
121-
parseSuperuserMaterial(conf);
115+
superuserMaterial = loadSuperuserMaterialInternal(conf);
116+
keystoresPassword = readSupersuperPassword();
122117
String localizationDir = service.toString() + "_" + LOCALIZATION_DIR_NAME;
123118
materializeDir = Paths.get(SYSTEM_TMP, localizationDir);
124119
File fileMaterializeDir = materializeDir.toFile();
@@ -143,6 +138,15 @@ protected void serviceInit(Configuration conf) throws Exception {
143138
super.serviceInit(conf);
144139
}
145140

141+
private X509SecurityMaterial loadSuperuserMaterialInternal(Configuration conf) throws IOException {
142+
SuperuserKeystoresLoader superuserKeystoresLoader = new SuperuserKeystoresLoader(conf);
143+
return superuserKeystoresLoader.loadSuperUserMaterial();
144+
}
145+
146+
public char[] readSupersuperPassword() throws IOException {
147+
return FileUtils.readFileToString(superuserMaterial.getPasswdLocation().toFile()).toCharArray();
148+
}
149+
146150
@Override
147151
protected void serviceStart() throws Exception {
148152
localizationEventsHandler = createLocalizationEventsHandler();
@@ -155,61 +159,45 @@ protected void serviceStart() throws Exception {
155159

156160
super.serviceStart();
157161
}
158-
159-
private void parseSuperuserMaterial(Configuration conf) {
160-
Configuration sslConf = new Configuration(false);
161-
sslConf.addResource(conf.get(SSLFactory.SSL_SERVER_CONF_KEY,
162-
"ssl-server.xml"));
163-
superKeystoreLocation = sslConf.get(
164-
FileBasedKeyStoresFactory.resolvePropertyName(SSLFactory.Mode.SERVER,
165-
FileBasedKeyStoresFactory.SSL_KEYSTORE_LOCATION_TPL_KEY));
166-
superKeystorePass = sslConf.get(
167-
FileBasedKeyStoresFactory.resolvePropertyName(SSLFactory.Mode.SERVER,
168-
FileBasedKeyStoresFactory.SSL_KEYSTORE_PASSWORD_TPL_KEY));
169-
superKeyPassword = sslConf.get(
170-
FileBasedKeyStoresFactory.resolvePropertyName(SSLFactory.Mode.SERVER,
171-
FileBasedKeyStoresFactory.SSL_KEYSTORE_KEYPASSWORD_TPL_KEY));
172-
superTrustStoreLocation = sslConf.get(
173-
FileBasedKeyStoresFactory.resolvePropertyName(SSLFactory.Mode.SERVER,
174-
FileBasedKeyStoresFactory.SSL_TRUSTSTORE_LOCATION_TPL_KEY));
175-
superTruststorePass = sslConf.get(
176-
FileBasedKeyStoresFactory.resolvePropertyName(SSLFactory.Mode.SERVER,
177-
FileBasedKeyStoresFactory.SSL_TRUSTSTORE_PASSWORD_TPL_KEY));
178-
}
179162

180163
// This method is accessible only from RM or NM. In any other case
181164
// CertificateLocalizationService is null
182165
@Override
183166
public String getSuperKeystoreLocation() {
184-
return superKeystoreLocation;
167+
return superuserMaterial.getKeyStoreLocation().toString();
185168
}
186169

187170
// This method is accessible only from RM or NM. In any other case
188171
// CertificateLocalizationService is null
189172
@Override
190173
public String getSuperKeystorePass() {
191-
return superKeystorePass;
174+
return String.valueOf(keystoresPassword);
192175
}
193176

194177
// This method is accessible only from RM or NM. In any other case
195178
// CertificateLocalizationService is null
196179
@Override
197180
public String getSuperKeyPassword() {
198-
return superKeyPassword;
181+
return String.valueOf(keystoresPassword);
199182
}
200183

201184
// This method is accessible only from RM or NM. In any other case
202185
// CertificateLocalizationService is null
203186
@Override
204187
public String getSuperTruststoreLocation() {
205-
return superTrustStoreLocation;
188+
return superuserMaterial.getTrustStoreLocation().toString();
206189
}
207190

208191
// This method is accessible only from RM or NM. In any other case
209192
// CertificateLocalizationService is null
210193
@Override
211194
public String getSuperTruststorePass() {
212-
return superTruststorePass;
195+
return String.valueOf(keystoresPassword);
196+
}
197+
198+
@Override
199+
public String getSuperMaterialPasswordFile() {
200+
return superuserMaterial.getPasswdLocation().toString();
213201
}
214202

215203
@Override
@@ -226,6 +214,10 @@ protected void serviceStop() throws Exception {
226214
FileUtils.deleteQuietly(materializeDir.toFile());
227215
}
228216

217+
for (int i = 0; i < keystoresPassword.length; i++) {
218+
keystoresPassword[i] = 'x';
219+
}
220+
229221
LOG.debug("Stopped CertificateLocalization service");
230222
super.serviceStop();
231223
}
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
* <p>
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
* <p>
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package io.hops.security;
19+
20+
import com.google.common.base.Strings;
21+
import org.apache.commons.logging.Log;
22+
import org.apache.commons.logging.LogFactory;
23+
import org.apache.hadoop.conf.Configuration;
24+
import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
25+
import org.apache.hadoop.net.HopsSSLSocketFactory;
26+
import org.apache.hadoop.net.hopssslchecks.HopsSSLCryptoMaterial;
27+
import org.apache.hadoop.security.UserGroupInformation;
28+
import org.apache.hadoop.security.ssl.FileBasedKeyStoresFactory;
29+
import org.apache.hadoop.security.ssl.KeyStoresFactory;
30+
import org.apache.hadoop.security.ssl.ReloadingX509KeyManager;
31+
import org.apache.hadoop.security.ssl.ReloadingX509TrustManager;
32+
import org.apache.hadoop.security.ssl.SSLFactory;
33+
34+
import javax.net.ssl.KeyManager;
35+
import javax.net.ssl.KeyManagerFactory;
36+
import javax.net.ssl.TrustManager;
37+
import java.io.IOException;
38+
import java.security.GeneralSecurityException;
39+
import java.security.KeyStore;
40+
import java.util.concurrent.TimeUnit;
41+
42+
import static org.apache.hadoop.security.ssl.FileBasedKeyStoresFactory.DEFAULT_SSL_KEYSTORE_RELOAD_INTERVAL;
43+
import static org.apache.hadoop.security.ssl.FileBasedKeyStoresFactory.DEFAULT_SSL_KEYSTORE_RELOAD_TIMEUNIT;
44+
import static org.apache.hadoop.security.ssl.FileBasedKeyStoresFactory.DEFAULT_SSL_TRUSTSTORE_RELOAD_INTERVAL;
45+
import static org.apache.hadoop.security.ssl.FileBasedKeyStoresFactory.SSL_KEYSTORE_KEYPASSWORD_TPL_KEY;
46+
import static org.apache.hadoop.security.ssl.FileBasedKeyStoresFactory.SSL_KEYSTORE_LOCATION_TPL_KEY;
47+
import static org.apache.hadoop.security.ssl.FileBasedKeyStoresFactory.SSL_KEYSTORE_PASSWORD_TPL_KEY;
48+
import static org.apache.hadoop.security.ssl.FileBasedKeyStoresFactory.SSL_KEYSTORE_RELOAD_INTERVAL_TPL_KEY;
49+
import static org.apache.hadoop.security.ssl.FileBasedKeyStoresFactory.SSL_KEYSTORE_RELOAD_TIMEUNIT_TPL_KEY;
50+
import static org.apache.hadoop.security.ssl.FileBasedKeyStoresFactory.SSL_PASSWORDFILE_LOCATION_TPL_KEY;
51+
import static org.apache.hadoop.security.ssl.FileBasedKeyStoresFactory.SSL_TRUSTSTORE_LOCATION_TPL_KEY;
52+
import static org.apache.hadoop.security.ssl.FileBasedKeyStoresFactory.SSL_TRUSTSTORE_RELOAD_INTERVAL_TPL_KEY;
53+
54+
public class HopsFileBasedKeyStoresFactory implements KeyStoresFactory {
55+
private static final Log LOG = LogFactory.getLog(HopsFileBasedKeyStoresFactory.class);
56+
57+
private Configuration sslConf;
58+
private Configuration systemConf;
59+
private ReloadingX509KeyManager keyManager;
60+
private KeyManager[] keyManagers;
61+
private ReloadingX509TrustManager trustManager;
62+
private TrustManager[] trustManagers;
63+
64+
@Override
65+
public void init(SSLFactory.Mode mode) throws IOException, GeneralSecurityException {
66+
HopsSSLCryptoMaterial material = loadCryptoMaterial(mode);
67+
createKeyManagers(mode, material);
68+
createTrustManagers(mode, material);
69+
}
70+
71+
public HopsSSLCryptoMaterial loadCryptoMaterial(SSLFactory.Mode mode) throws IOException {
72+
try {
73+
CertificateLocalizationCtx certificateLocalizationCtx = CertificateLocalizationCtx.getInstance();
74+
certificateLocalizationCtx.setProxySuperusers(systemConf);
75+
Configuration x509MaterialConf = new Configuration(false);
76+
x509MaterialConf.set(CommonConfigurationKeysPublic.HOPS_TLS_SUPER_MATERIAL_DIRECTORY,
77+
systemConf.get(CommonConfigurationKeysPublic.HOPS_TLS_SUPER_MATERIAL_DIRECTORY, ""));
78+
// Create a HopsSSLSocketFactory to use its functionality of identifying the correct security material
79+
// We don't use the socket factory anywhere else in this class
80+
HopsSSLSocketFactory hopsSSLSocketFactory = new HopsSSLSocketFactory();
81+
hopsSSLSocketFactory.setConf(x509MaterialConf);
82+
return hopsSSLSocketFactory.configureCryptoMaterial(
83+
certificateLocalizationCtx.getCertificateLocalization(), certificateLocalizationCtx.getProxySuperusers());
84+
} catch (Exception ex) {
85+
UserGroupInformation currentUser = UserGroupInformation.getCurrentUser();
86+
LOG.warn("Could not locate cryptographic material for <" + currentUser.getUserName()
87+
+ "> Falling back to ssl-{client,server}.xml");
88+
// Fallback to old-school ssl-{client,server}.xml
89+
String keystoreLocationProperty = FileBasedKeyStoresFactory.resolvePropertyName(mode,
90+
SSL_KEYSTORE_LOCATION_TPL_KEY);
91+
String keystoreLocation = sslConf.get(keystoreLocationProperty);
92+
String keystorePasswordProperty = FileBasedKeyStoresFactory.resolvePropertyName(mode,
93+
SSL_KEYSTORE_PASSWORD_TPL_KEY);
94+
String keystorePassword = sslConf.get(keystorePasswordProperty);
95+
String keyPasswordProperty =
96+
FileBasedKeyStoresFactory.resolvePropertyName(mode, SSL_KEYSTORE_KEYPASSWORD_TPL_KEY);
97+
String keyPassword = sslConf.get(keyPasswordProperty, keystorePassword);
98+
99+
String truststoreLocationProperty = FileBasedKeyStoresFactory.resolvePropertyName(mode,
100+
SSL_TRUSTSTORE_LOCATION_TPL_KEY);
101+
String truststoreLocation = sslConf.get(truststoreLocationProperty);
102+
String passwordFileLocationProperty =
103+
FileBasedKeyStoresFactory.resolvePropertyName(mode,
104+
SSL_PASSWORDFILE_LOCATION_TPL_KEY);
105+
String passwordFileLocation = sslConf.get(passwordFileLocationProperty, null);
106+
if (Strings.isNullOrEmpty(keystoreLocation) || Strings.isNullOrEmpty(truststoreLocation)
107+
|| Strings.isNullOrEmpty(keystorePassword) || Strings.isNullOrEmpty(keyPassword)) {
108+
throw new IOException("Failed to determine cryptographic material for user <" + currentUser.getUserName()
109+
+ ">. Exhausted all methods!");
110+
}
111+
return new HopsSSLCryptoMaterial(
112+
keystoreLocation, keystorePassword, keyPassword,
113+
truststoreLocation, keystorePassword,
114+
passwordFileLocation, true);
115+
}
116+
}
117+
118+
@Override
119+
public void destroy() {
120+
if (trustManager != null) {
121+
trustManager.destroy();
122+
trustManager = null;
123+
trustManagers = null;
124+
}
125+
if (keyManager != null) {
126+
keyManager.stop();
127+
keyManager = null;
128+
keyManagers = null;
129+
}
130+
}
131+
132+
@Override
133+
public KeyManager[] getKeyManagers() {
134+
return keyManagers;
135+
}
136+
137+
@Override
138+
public TrustManager[] getTrustManagers() {
139+
return trustManagers;
140+
}
141+
142+
@Override
143+
public void setConf(Configuration conf) {
144+
this.sslConf = conf;
145+
}
146+
147+
@Override
148+
public Configuration getConf() {
149+
return sslConf;
150+
}
151+
152+
public void setSystemConf(Configuration conf) {
153+
this.systemConf = conf;
154+
}
155+
156+
public Configuration getSystemConf() {
157+
return systemConf;
158+
}
159+
160+
private void createKeyManagers(SSLFactory.Mode mode, HopsSSLCryptoMaterial material)
161+
throws IOException, GeneralSecurityException {
162+
boolean requireClientCert = sslConf.getBoolean(SSLFactory.SSL_REQUIRE_CLIENT_CERT_KEY,
163+
SSLFactory.SSL_REQUIRE_CLIENT_CERT_DEFAULT);
164+
165+
String keystoreType = sslConf.get(
166+
FileBasedKeyStoresFactory.resolvePropertyName(mode, FileBasedKeyStoresFactory.SSL_KEYSTORE_TYPE_TPL_KEY),
167+
FileBasedKeyStoresFactory.DEFAULT_KEYSTORE_TYPE);
168+
169+
if (requireClientCert || mode == SSLFactory.Mode.SERVER) {
170+
171+
String keystoreLocation = material.getKeyStoreLocation();
172+
if (Strings.isNullOrEmpty(keystoreLocation)) {
173+
throw new GeneralSecurityException("Could not identify correct keystore");
174+
}
175+
String keystorePassword = material.getKeyStorePassword();
176+
if (Strings.isNullOrEmpty(keystorePassword)) {
177+
throw new GeneralSecurityException("Could not load keystore password");
178+
}
179+
String keyPassword = material.getKeyPassword();
180+
if (Strings.isNullOrEmpty(keyPassword)) {
181+
throw new GeneralSecurityException("Could not load key password");
182+
}
183+
184+
long keyStoreReloadInterval = sslConf.getLong(
185+
FileBasedKeyStoresFactory.resolvePropertyName(mode, SSL_KEYSTORE_RELOAD_INTERVAL_TPL_KEY),
186+
DEFAULT_SSL_KEYSTORE_RELOAD_INTERVAL);
187+
String timeUnitStr = sslConf.get(
188+
FileBasedKeyStoresFactory.resolvePropertyName(mode, SSL_KEYSTORE_RELOAD_TIMEUNIT_TPL_KEY),
189+
DEFAULT_SSL_KEYSTORE_RELOAD_TIMEUNIT);
190+
TimeUnit reloadTimeUnit = TimeUnit.valueOf(timeUnitStr.toUpperCase());
191+
192+
String passwordFileLocation = material.getPasswordFileLocation();
193+
keyManager = new ReloadingX509KeyManager(keystoreType, keystoreLocation, keystorePassword, passwordFileLocation,
194+
keyPassword, keyStoreReloadInterval, reloadTimeUnit);
195+
196+
keyManager.init();
197+
if (LOG.isDebugEnabled()) {
198+
LOG.debug(mode.toString() + " Loaded KeyStore: " + keystoreLocation);
199+
}
200+
keyManagers = new KeyManager[]{keyManager};
201+
} else {
202+
KeyStore keyStore = KeyStore.getInstance(keystoreType);
203+
keyStore.load(null, null);
204+
KeyManagerFactory keyMgrFactory = KeyManagerFactory.getInstance(SSLFactory.SSLCERTIFICATE);
205+
keyMgrFactory.init(keyStore, null);
206+
keyManagers = keyMgrFactory.getKeyManagers();
207+
}
208+
}
209+
210+
private void createTrustManagers(SSLFactory.Mode mode, HopsSSLCryptoMaterial material)
211+
throws IOException, GeneralSecurityException {
212+
String truststoreType = sslConf.get(
213+
FileBasedKeyStoresFactory.resolvePropertyName(mode, FileBasedKeyStoresFactory.SSL_TRUSTSTORE_TYPE_TPL_KEY),
214+
FileBasedKeyStoresFactory.DEFAULT_KEYSTORE_TYPE);
215+
String truststoreLocation = material.getTrustStoreLocation();
216+
if (Strings.isNullOrEmpty(truststoreLocation)) {
217+
throw new GeneralSecurityException("Could not identify correct truststore");
218+
}
219+
String truststorePassword = material.getTrustStorePassword();
220+
if (Strings.isNullOrEmpty(truststorePassword)) {
221+
throw new GeneralSecurityException("Could not load truststore password");
222+
}
223+
String passwordFileLocation = material.getPasswordFileLocation();
224+
long truststoreReloadInterval =
225+
sslConf.getLong(
226+
FileBasedKeyStoresFactory.resolvePropertyName(mode, SSL_TRUSTSTORE_RELOAD_INTERVAL_TPL_KEY),
227+
DEFAULT_SSL_TRUSTSTORE_RELOAD_INTERVAL);
228+
if (LOG.isDebugEnabled()) {
229+
LOG.debug(mode.toString() + " TrustStore: " + truststoreLocation);
230+
}
231+
trustManager = new ReloadingX509TrustManager(truststoreType,
232+
truststoreLocation, truststorePassword, passwordFileLocation, truststoreReloadInterval);
233+
trustManager.init();
234+
if (LOG.isDebugEnabled()) {
235+
LOG.debug(mode.toString() + " Loaded TrustStore: " + truststoreLocation);
236+
}
237+
trustManagers = new TrustManager[]{trustManager};
238+
}
239+
}

0 commit comments

Comments
 (0)