Make PKI BootstrapCheck work with SecureSettings (elastic/x-pack-elasticsearch#3993)
SslConfiguration can depend on SecureSettings, so it must be constructed during the correct lifecycle phase. For PkiRealmBootstrapCheck, moved the construction of SslConfiguration objets into the constructor rather than the check method Original commit: elastic/x-pack-elasticsearch@1a4d147216
This commit is contained in:
parent
d31d90d378
commit
41af46688a
|
@ -274,6 +274,13 @@ public class SSLService extends AbstractComponent {
|
||||||
*/
|
*/
|
||||||
public boolean isSSLClientAuthEnabled(Settings settings, Settings fallback) {
|
public boolean isSSLClientAuthEnabled(Settings settings, Settings fallback) {
|
||||||
SSLConfiguration sslConfiguration = sslConfiguration(settings, fallback);
|
SSLConfiguration sslConfiguration = sslConfiguration(settings, fallback);
|
||||||
|
return isSSLClientAuthEnabled(sslConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether client authentication is enabled for a particular configuration
|
||||||
|
*/
|
||||||
|
public boolean isSSLClientAuthEnabled(SSLConfiguration sslConfiguration) {
|
||||||
return sslConfiguration.sslClientAuth().enabled();
|
return sslConfiguration.sslClientAuth().enabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,11 @@ import org.elasticsearch.xpack.core.XPackSettings;
|
||||||
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
|
import org.elasticsearch.xpack.core.security.authc.RealmSettings;
|
||||||
import org.elasticsearch.xpack.core.security.authc.pki.PkiRealmSettings;
|
import org.elasticsearch.xpack.core.security.authc.pki.PkiRealmSettings;
|
||||||
import org.elasticsearch.xpack.core.security.transport.netty4.SecurityNetty4Transport;
|
import org.elasticsearch.xpack.core.security.transport.netty4.SecurityNetty4Transport;
|
||||||
|
import org.elasticsearch.xpack.core.ssl.SSLConfiguration;
|
||||||
import org.elasticsearch.xpack.core.ssl.SSLService;
|
import org.elasticsearch.xpack.core.ssl.SSLService;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.elasticsearch.xpack.core.XPackSettings.HTTP_SSL_ENABLED;
|
import static org.elasticsearch.xpack.core.XPackSettings.HTTP_SSL_ENABLED;
|
||||||
|
@ -22,9 +25,34 @@ import static org.elasticsearch.xpack.core.security.SecurityField.setting;
|
||||||
class PkiRealmBootstrapCheck implements BootstrapCheck {
|
class PkiRealmBootstrapCheck implements BootstrapCheck {
|
||||||
|
|
||||||
private final SSLService sslService;
|
private final SSLService sslService;
|
||||||
|
private final List<SSLConfiguration> sslConfigurations;
|
||||||
|
|
||||||
PkiRealmBootstrapCheck(SSLService sslService) {
|
PkiRealmBootstrapCheck(Settings settings, SSLService sslService) {
|
||||||
this.sslService = sslService;
|
this.sslService = sslService;
|
||||||
|
this.sslConfigurations = loadSslConfigurations(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link SSLConfiguration} may depend on {@link org.elasticsearch.common.settings.SecureSettings} that can only be read during startup.
|
||||||
|
* We need to preload these during component configuration.
|
||||||
|
*/
|
||||||
|
private List<SSLConfiguration> loadSslConfigurations(Settings settings) {
|
||||||
|
final List<SSLConfiguration> list = new ArrayList<>();
|
||||||
|
if (HTTP_SSL_ENABLED.get(settings)) {
|
||||||
|
list.add(sslService.sslConfiguration(SSLService.getHttpTransportSSLSettings(settings), Settings.EMPTY));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (XPackSettings.TRANSPORT_SSL_ENABLED.get(settings)) {
|
||||||
|
final Settings transportSslSettings = settings.getByPrefix(setting("transport.ssl."));
|
||||||
|
list.add(sslService.sslConfiguration(transportSslSettings, Settings.EMPTY));
|
||||||
|
|
||||||
|
settings.getGroups("transport.profiles.").values().stream()
|
||||||
|
.map(SecurityNetty4Transport::profileSslSettings)
|
||||||
|
.map(s -> sslService.sslConfiguration(s, transportSslSettings))
|
||||||
|
.forEach(list::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,27 +66,8 @@ class PkiRealmBootstrapCheck implements BootstrapCheck {
|
||||||
.filter(s -> PkiRealmSettings.TYPE.equals(s.get("type")))
|
.filter(s -> PkiRealmSettings.TYPE.equals(s.get("type")))
|
||||||
.anyMatch(s -> s.getAsBoolean("enabled", true));
|
.anyMatch(s -> s.getAsBoolean("enabled", true));
|
||||||
if (pkiRealmEnabled) {
|
if (pkiRealmEnabled) {
|
||||||
// HTTP
|
for (SSLConfiguration configuration : this.sslConfigurations) {
|
||||||
final boolean httpSsl = HTTP_SSL_ENABLED.get(settings);
|
if (sslService.isSSLClientAuthEnabled(configuration)) {
|
||||||
Settings httpSSLSettings = SSLService.getHttpTransportSSLSettings(settings);
|
|
||||||
final boolean httpClientAuth = sslService.isSSLClientAuthEnabled(httpSSLSettings);
|
|
||||||
if (httpSsl && httpClientAuth) {
|
|
||||||
return BootstrapCheckResult.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default Transport
|
|
||||||
final boolean transportSSLEnabled = XPackSettings.TRANSPORT_SSL_ENABLED.get(settings);
|
|
||||||
final Settings transportSSLSettings = settings.getByPrefix(setting("transport.ssl."));
|
|
||||||
final boolean clientAuthEnabled = sslService.isSSLClientAuthEnabled(transportSSLSettings);
|
|
||||||
if (transportSSLEnabled && clientAuthEnabled) {
|
|
||||||
return BootstrapCheckResult.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transport Profiles
|
|
||||||
Map<String, Settings> groupedSettings = settings.getGroups("transport.profiles.");
|
|
||||||
for (Map.Entry<String, Settings> entry : groupedSettings.entrySet()) {
|
|
||||||
if (transportSSLEnabled && sslService.isSSLClientAuthEnabled(
|
|
||||||
SecurityNetty4Transport.profileSslSettings(entry.getValue()), transportSSLSettings)) {
|
|
||||||
return BootstrapCheckResult.success();
|
return BootstrapCheckResult.success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -283,7 +283,7 @@ public class Security extends Plugin implements ActionPlugin, IngestPlugin, Netw
|
||||||
final List<BootstrapCheck> checks = new ArrayList<>();
|
final List<BootstrapCheck> checks = new ArrayList<>();
|
||||||
checks.addAll(Arrays.asList(
|
checks.addAll(Arrays.asList(
|
||||||
new TokenSSLBootstrapCheck(),
|
new TokenSSLBootstrapCheck(),
|
||||||
new PkiRealmBootstrapCheck(getSslService()),
|
new PkiRealmBootstrapCheck(settings, getSslService()),
|
||||||
new TLSLicenseBootstrapCheck()));
|
new TLSLicenseBootstrapCheck()));
|
||||||
checks.addAll(InternalRealms.getBootstrapChecks(settings, env));
|
checks.addAll(InternalRealms.getBootstrapChecks(settings, env));
|
||||||
this.bootstrapChecks = Collections.unmodifiableList(checks);
|
this.bootstrapChecks = Collections.unmodifiableList(checks);
|
||||||
|
|
|
@ -5,20 +5,23 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.security;
|
package org.elasticsearch.xpack.security;
|
||||||
|
|
||||||
|
import org.elasticsearch.bootstrap.BootstrapCheck;
|
||||||
import org.elasticsearch.bootstrap.BootstrapContext;
|
import org.elasticsearch.bootstrap.BootstrapContext;
|
||||||
|
import org.elasticsearch.common.settings.MockSecureSettings;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.env.Environment;
|
import org.elasticsearch.env.Environment;
|
||||||
import org.elasticsearch.env.TestEnvironment;
|
import org.elasticsearch.env.TestEnvironment;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
import org.elasticsearch.xpack.core.security.authc.pki.PkiRealmSettings;
|
import org.elasticsearch.xpack.core.security.authc.pki.PkiRealmSettings;
|
||||||
import org.elasticsearch.xpack.core.ssl.SSLService;
|
import org.elasticsearch.xpack.core.ssl.SSLService;
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
|
|
||||||
public class PkiRealmBootstrapCheckTests extends ESTestCase {
|
public class PkiRealmBootstrapCheckTests extends ESTestCase {
|
||||||
|
|
||||||
public void testPkiRealmBootstrapDefault() throws Exception {
|
public void testPkiRealmBootstrapDefault() throws Exception {
|
||||||
assertFalse(new PkiRealmBootstrapCheck(new SSLService(Settings.EMPTY,
|
final Settings settings = Settings.EMPTY;
|
||||||
TestEnvironment.newEnvironment(Settings.builder().put("path.home", createTempDir()).build()))).check(
|
final Environment env = TestEnvironment.newEnvironment(Settings.builder().put("path.home", createTempDir()).build());
|
||||||
new BootstrapContext(Settings.EMPTY, null)).isFailure());
|
assertFalse(runCheck(settings, env).isFailure());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testBootstrapCheckWithPkiRealm() throws Exception {
|
public void testBootstrapCheckWithPkiRealm() throws Exception {
|
||||||
|
@ -27,48 +30,48 @@ public class PkiRealmBootstrapCheckTests extends ESTestCase {
|
||||||
.put("path.home", createTempDir())
|
.put("path.home", createTempDir())
|
||||||
.build();
|
.build();
|
||||||
Environment env = TestEnvironment.newEnvironment(settings);
|
Environment env = TestEnvironment.newEnvironment(settings);
|
||||||
assertTrue(new PkiRealmBootstrapCheck(new SSLService(settings, env)).check(new BootstrapContext(settings, null)).isFailure());
|
assertTrue(runCheck(settings, env).isFailure());
|
||||||
|
|
||||||
// enable transport tls
|
// enable transport tls
|
||||||
settings = Settings.builder().put(settings)
|
settings = Settings.builder().put(settings)
|
||||||
.put("xpack.security.transport.ssl.enabled", true)
|
.put("xpack.security.transport.ssl.enabled", true)
|
||||||
.build();
|
.build();
|
||||||
assertFalse(new PkiRealmBootstrapCheck(new SSLService(settings, env)).check(new BootstrapContext(settings, null)).isFailure());
|
assertFalse(runCheck(settings, env).isFailure());
|
||||||
|
|
||||||
// disable client auth default
|
// disable client auth default
|
||||||
settings = Settings.builder().put(settings)
|
settings = Settings.builder().put(settings)
|
||||||
.put("xpack.ssl.client_authentication", "none")
|
.put("xpack.ssl.client_authentication", "none")
|
||||||
.build();
|
.build();
|
||||||
env = TestEnvironment.newEnvironment(settings);
|
env = TestEnvironment.newEnvironment(settings);
|
||||||
assertTrue(new PkiRealmBootstrapCheck(new SSLService(settings, env)).check(new BootstrapContext(settings, null)).isFailure());
|
assertTrue(runCheck(settings, env).isFailure());
|
||||||
|
|
||||||
// enable ssl for http
|
// enable ssl for http
|
||||||
settings = Settings.builder().put(settings)
|
settings = Settings.builder().put(settings)
|
||||||
.put("xpack.security.http.ssl.enabled", true)
|
.put("xpack.security.http.ssl.enabled", true)
|
||||||
.build();
|
.build();
|
||||||
env = TestEnvironment.newEnvironment(settings);
|
env = TestEnvironment.newEnvironment(settings);
|
||||||
assertTrue(new PkiRealmBootstrapCheck(new SSLService(settings, env)).check(new BootstrapContext(settings, null)).isFailure());
|
assertTrue(runCheck(settings, env).isFailure());
|
||||||
|
|
||||||
// enable client auth for http
|
// enable client auth for http
|
||||||
settings = Settings.builder().put(settings)
|
settings = Settings.builder().put(settings)
|
||||||
.put("xpack.security.http.ssl.client_authentication", randomFrom("required", "optional"))
|
.put("xpack.security.http.ssl.client_authentication", randomFrom("required", "optional"))
|
||||||
.build();
|
.build();
|
||||||
env = TestEnvironment.newEnvironment(settings);
|
env = TestEnvironment.newEnvironment(settings);
|
||||||
assertFalse(new PkiRealmBootstrapCheck(new SSLService(settings, env)).check(new BootstrapContext(settings, null)).isFailure());
|
assertFalse(runCheck(settings, env).isFailure());
|
||||||
|
|
||||||
// disable http ssl
|
// disable http ssl
|
||||||
settings = Settings.builder().put(settings)
|
settings = Settings.builder().put(settings)
|
||||||
.put("xpack.security.http.ssl.enabled", false)
|
.put("xpack.security.http.ssl.enabled", false)
|
||||||
.build();
|
.build();
|
||||||
env = TestEnvironment.newEnvironment(settings);
|
env = TestEnvironment.newEnvironment(settings);
|
||||||
assertTrue(new PkiRealmBootstrapCheck(new SSLService(settings, env)).check(new BootstrapContext(settings, null)).isFailure());
|
assertTrue(runCheck(settings, env).isFailure());
|
||||||
|
|
||||||
// set transport client auth
|
// set transport client auth
|
||||||
settings = Settings.builder().put(settings)
|
settings = Settings.builder().put(settings)
|
||||||
.put("xpack.security.transport.client_authentication", randomFrom("required", "optional"))
|
.put("xpack.security.transport.client_authentication", randomFrom("required", "optional"))
|
||||||
.build();
|
.build();
|
||||||
env = TestEnvironment.newEnvironment(settings);
|
env = TestEnvironment.newEnvironment(settings);
|
||||||
assertTrue(new PkiRealmBootstrapCheck(new SSLService(settings, env)).check(new BootstrapContext(settings, null)).isFailure());
|
assertTrue(runCheck(settings, env).isFailure());
|
||||||
|
|
||||||
// test with transport profile
|
// test with transport profile
|
||||||
settings = Settings.builder().put(settings)
|
settings = Settings.builder().put(settings)
|
||||||
|
@ -76,7 +79,11 @@ public class PkiRealmBootstrapCheckTests extends ESTestCase {
|
||||||
.put("transport.profiles.foo.xpack.security.ssl.client_authentication", randomFrom("required", "optional"))
|
.put("transport.profiles.foo.xpack.security.ssl.client_authentication", randomFrom("required", "optional"))
|
||||||
.build();
|
.build();
|
||||||
env = TestEnvironment.newEnvironment(settings);
|
env = TestEnvironment.newEnvironment(settings);
|
||||||
assertFalse(new PkiRealmBootstrapCheck(new SSLService(settings, env)).check(new BootstrapContext(settings, null)).isFailure());
|
assertFalse(runCheck(settings, env).isFailure());
|
||||||
|
}
|
||||||
|
|
||||||
|
private BootstrapCheck.BootstrapCheckResult runCheck(Settings settings, Environment env) throws Exception {
|
||||||
|
return new PkiRealmBootstrapCheck(settings, new SSLService(settings, env)).check(new BootstrapContext(settings, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testBootstrapCheckWithDisabledRealm() throws Exception {
|
public void testBootstrapCheckWithDisabledRealm() throws Exception {
|
||||||
|
@ -87,6 +94,26 @@ public class PkiRealmBootstrapCheckTests extends ESTestCase {
|
||||||
.put("path.home", createTempDir())
|
.put("path.home", createTempDir())
|
||||||
.build();
|
.build();
|
||||||
Environment env = TestEnvironment.newEnvironment(settings);
|
Environment env = TestEnvironment.newEnvironment(settings);
|
||||||
assertFalse(new PkiRealmBootstrapCheck(new SSLService(settings, env)).check(new BootstrapContext(settings, null)).isFailure());
|
assertFalse(runCheck(settings, env).isFailure());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testBootstrapCheckWithClosedSecuredSetting() throws Exception {
|
||||||
|
final boolean expectFail = randomBoolean();
|
||||||
|
final MockSecureSettings secureSettings = new MockSecureSettings();
|
||||||
|
secureSettings.setString("xpack.security.http.ssl.keystore.secure_password", "testnode");
|
||||||
|
Settings settings = Settings.builder()
|
||||||
|
.put("xpack.security.authc.realms.test_pki.type", PkiRealmSettings.TYPE)
|
||||||
|
.put("xpack.security.http.ssl.enabled", true)
|
||||||
|
.put("xpack.security.http.ssl.client_authentication", expectFail ? "none" : "optional")
|
||||||
|
.put("xpack.security.http.ssl.keystore.path",
|
||||||
|
getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.jks"))
|
||||||
|
.put("path.home", createTempDir())
|
||||||
|
.setSecureSettings(secureSettings)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Environment env = TestEnvironment.newEnvironment(settings);
|
||||||
|
final PkiRealmBootstrapCheck check = new PkiRealmBootstrapCheck(settings, new SSLService(settings, env));
|
||||||
|
secureSettings.close();
|
||||||
|
assertThat(check.check(new BootstrapContext(settings, null)).isFailure(), Matchers.equalTo(expectFail));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue