Log the status of security on license change (#42741)
Whether security is enabled/disabled is dependent on the combination of the node settings and the cluster license. This commit adds a license state listener that logs when the license change causes security to switch state (or to be initialised). This is primarily useful for diagnosing cluster formation issues. Backport of: #42488
This commit is contained in:
parent
9035e61825
commit
8de3a88205
|
@ -117,7 +117,7 @@ public class MockLogAppender extends AbstractAppender {
|
|||
|
||||
@Override
|
||||
public void assertMatched() {
|
||||
assertThat("expected to see " + name + " but did not", saw, equalTo(false));
|
||||
assertThat("expected not to see " + name + " but did", saw, equalTo(false));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -226,6 +226,7 @@ import org.elasticsearch.xpack.security.rest.action.user.RestHasPrivilegesAction
|
|||
import org.elasticsearch.xpack.security.rest.action.user.RestPutUserAction;
|
||||
import org.elasticsearch.xpack.security.rest.action.user.RestSetEnabledAction;
|
||||
import org.elasticsearch.xpack.security.support.SecurityIndexManager;
|
||||
import org.elasticsearch.xpack.security.support.SecurityStatusChangeListener;
|
||||
import org.elasticsearch.xpack.security.transport.SecurityHttpSettings;
|
||||
import org.elasticsearch.xpack.security.transport.SecurityServerTransportInterceptor;
|
||||
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
||||
|
@ -461,6 +462,7 @@ public class Security extends Plugin implements ActionPlugin, IngestPlugin, Netw
|
|||
// to keep things simple, just invalidate all cached entries on license change. this happens so rarely that the impact should be
|
||||
// minimal
|
||||
getLicenseState().addListener(allRolesStore::invalidateAll);
|
||||
getLicenseState().addListener(new SecurityStatusChangeListener(getLicenseState()));
|
||||
|
||||
final AuthenticationFailureHandler failureHandler = createAuthenticationFailureHandler(realms);
|
||||
authcService.set(new AuthenticationService(settings, realms, auditTrailService, failureHandler, threadPool,
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.xpack.security.support;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.elasticsearch.license.LicenseStateListener;
|
||||
import org.elasticsearch.license.XPackLicenseState;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A listener for license state changes that provides log messages when a license change
|
||||
* causes security to switch between enable and disabled (or vice versa).
|
||||
*/
|
||||
public class SecurityStatusChangeListener implements LicenseStateListener {
|
||||
|
||||
private final Logger logger;
|
||||
private final XPackLicenseState licenseState;
|
||||
private Boolean securityEnabled;
|
||||
|
||||
public SecurityStatusChangeListener(XPackLicenseState licenseState) {
|
||||
this.logger = LogManager.getLogger(getClass());
|
||||
this.licenseState = licenseState;
|
||||
this.securityEnabled = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This listener will not be registered if security has been explicitly disabled, so we only need to account for dynamic changes due
|
||||
* to changes in the applied license.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void licenseStateChanged() {
|
||||
final boolean newState = licenseState.isSecurityAvailable() && licenseState.isSecurityDisabledByLicenseDefaults() == false;
|
||||
// old state might be null (undefined) so do Object comparison
|
||||
if (Objects.equals(newState, securityEnabled) == false) {
|
||||
logger.info("Active license is now [{}]; Security is {}", licenseState.getOperationMode(), newState ? "enabled" : "disabled");
|
||||
this.securityEnabled = newState;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.xpack.security.support;
|
||||
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.license.License;
|
||||
import org.elasticsearch.license.XPackLicenseState;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.test.MockLogAppender;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class SecurityStatusChangeListenerTests extends ESTestCase {
|
||||
|
||||
private XPackLicenseState licenseState;
|
||||
private SecurityStatusChangeListener listener;
|
||||
private MockLogAppender logAppender;
|
||||
private Logger listenerLogger;
|
||||
|
||||
@Before
|
||||
public void setup() throws IllegalAccessException {
|
||||
licenseState = Mockito.mock(XPackLicenseState.class);
|
||||
when(licenseState.isSecurityAvailable()).thenReturn(true);
|
||||
|
||||
listener = new SecurityStatusChangeListener(licenseState);
|
||||
|
||||
logAppender = new MockLogAppender();
|
||||
logAppender.start();
|
||||
listenerLogger = LogManager.getLogger(listener.getClass());
|
||||
Loggers.addAppender(listenerLogger, logAppender);
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
Loggers.removeAppender(listenerLogger, logAppender);
|
||||
logAppender.stop();
|
||||
}
|
||||
|
||||
public void testSecurityEnabledToDisabled() {
|
||||
when(licenseState.isSecurityDisabledByLicenseDefaults()).thenReturn(false);
|
||||
|
||||
when(licenseState.getOperationMode()).thenReturn(License.OperationMode.GOLD);
|
||||
logAppender.addExpectation(new MockLogAppender.SeenEventExpectation(
|
||||
"initial change",
|
||||
listener.getClass().getName(),
|
||||
Level.INFO,
|
||||
"Active license is now [GOLD]; Security is enabled"
|
||||
));
|
||||
listener.licenseStateChanged();
|
||||
|
||||
when(licenseState.getOperationMode()).thenReturn(License.OperationMode.PLATINUM);
|
||||
logAppender.addExpectation(new MockLogAppender.UnseenEventExpectation(
|
||||
"no-op change",
|
||||
listener.getClass().getName(),
|
||||
Level.INFO,
|
||||
"Active license is now [PLATINUM]; Security is enabled"
|
||||
));
|
||||
|
||||
when(licenseState.isSecurityDisabledByLicenseDefaults()).thenReturn(true);
|
||||
when(licenseState.getOperationMode()).thenReturn(License.OperationMode.BASIC);
|
||||
logAppender.addExpectation(new MockLogAppender.SeenEventExpectation(
|
||||
"change to basic",
|
||||
listener.getClass().getName(),
|
||||
Level.INFO,
|
||||
"Active license is now [BASIC]; Security is disabled"
|
||||
));
|
||||
listener.licenseStateChanged();
|
||||
|
||||
logAppender.assertAllExpectationsMatched();
|
||||
}
|
||||
|
||||
public void testSecurityDisabledToEnabled() {
|
||||
when(licenseState.isSecurityDisabledByLicenseDefaults()).thenReturn(true);
|
||||
|
||||
when(licenseState.getOperationMode()).thenReturn(License.OperationMode.TRIAL);
|
||||
logAppender.addExpectation(new MockLogAppender.SeenEventExpectation(
|
||||
"initial change",
|
||||
listener.getClass().getName(),
|
||||
Level.INFO,
|
||||
"Active license is now [TRIAL]; Security is disabled"
|
||||
));
|
||||
listener.licenseStateChanged();
|
||||
|
||||
when(licenseState.getOperationMode()).thenReturn(License.OperationMode.BASIC);
|
||||
logAppender.addExpectation(new MockLogAppender.UnseenEventExpectation(
|
||||
"no-op change",
|
||||
listener.getClass().getName(),
|
||||
Level.INFO,
|
||||
"Active license is now [BASIC]; Security is disabled"
|
||||
));
|
||||
|
||||
when(licenseState.isSecurityDisabledByLicenseDefaults()).thenReturn(false);
|
||||
when(licenseState.getOperationMode()).thenReturn(License.OperationMode.PLATINUM);
|
||||
logAppender.addExpectation(new MockLogAppender.SeenEventExpectation(
|
||||
"change to platinum",
|
||||
listener.getClass().getName(),
|
||||
Level.INFO,
|
||||
"Active license is now [PLATINUM]; Security is enabled"
|
||||
));
|
||||
listener.licenseStateChanged();
|
||||
|
||||
logAppender.assertAllExpectationsMatched();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue