Skip to content

Commit

Permalink
Introducing passive_intertransport_auth to facilitate communication b… (
Browse files Browse the repository at this point in the history
opensearch-project#1156)

* Introducing passive_intertransport_auth to facilitate communication between nodes with adv sec enabled and nodes without adv sec enabled.

Changes to ssl_dual_mode_enabled to support the same.

Signed-off-by: Dhiresh Jain <dhireshj@amazon.com>

* Addressed comments

Signed-off-by: Dhiresh Jain <dhireshj@amazon.com>

* Minor fix

Signed-off-by: Dhiresh Jain <dhireshj@amazon.com>

* Modifying transportInterClusterPassiveAuth to be controlled by cluster setting instead of opendistro config

Signed-off-by: Dhiresh Jain <dhireshj@amazon.com>

* Fixing unit tests

Signed-off-by: Dhiresh Jain <dhireshj@amazon.com>

* Resolving conflicts with mainline

Signed-off-by: Dhiresh Jain <dhireshj@amazon.com>

* Removing Filtered property from new setting, improving code readability

Signed-off-by: Dhiresh Jain <dhireshj@amazon.com>

* Fixing UTs where node space causing shards to be unassigned

Signed-off-by: Dhiresh Jain <dhireshj@amazon.com>

* Reverting cluster setting in UT

Signed-off-by: Dhiresh Jain <dhireshj@amazon.com>

* Addressing minor comment on UT

Signed-off-by: Dhiresh Jain <dhireshj@amazon.com>
  • Loading branch information
dhiAmzn authored Jun 9, 2021
1 parent deac07f commit ae628a5
Show file tree
Hide file tree
Showing 28 changed files with 2,795 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,11 @@
import org.opensearch.security.ssl.OpenSearchSecuritySSLPlugin;
import org.opensearch.security.ssl.rest.SecuritySSLReloadCertsAction;
import org.opensearch.security.ssl.rest.SecuritySSLCertsInfoAction;

import org.opensearch.security.ssl.transport.DefaultPrincipalExtractor;
import org.opensearch.security.transport.SecurityInterceptor;
import org.opensearch.security.setting.OpensearchDynamicSetting;
import org.opensearch.security.setting.TransportPassiveAuthSetting;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.lucene.search.QueryCachingPolicy;
Expand Down Expand Up @@ -200,6 +202,7 @@ public final class OpenSearchSecurityPlugin extends OpenSearchSecuritySSLPlugin
private volatile NamedXContentRegistry namedXContentRegistry = null;
private volatile DlsFlsRequestValve dlsFlsValve = null;
private volatile Salt salt;
private volatile OpensearchDynamicSetting<Boolean> transportPassiveAuthSetting;

public static boolean isActionTraceEnabled() {
return actionTrace.isTraceEnabled();
Expand Down Expand Up @@ -248,6 +251,8 @@ public OpenSearchSecurityPlugin(final Settings settings, final Path configPath)
disabled = isDisabled(settings);
sslCertReloadEnabled = isSslCertReloadEnabled(settings);

transportPassiveAuthSetting = new TransportPassiveAuthSetting(settings);

if (disabled) {
this.sslCertReloadEnabled = false;
log.warn("OpenSearch Security plugin installed but disabled. This can expose your configuration (including passwords) to the public.");
Expand Down Expand Up @@ -740,6 +745,10 @@ public Collection<Object> createComponents(Client localClient, ClusterService cl
if (client || disabled) {
return components;
}

//Register opensearch dynamic settings
transportPassiveAuthSetting.registerClusterSettingsChangeListener(clusterService.getClusterSettings());

final ClusterInfoHolder cih = new ClusterInfoHolder();
this.cs.addListener(cih);
this.salt = Salt.from(settings);
Expand Down Expand Up @@ -778,7 +787,7 @@ public Collection<Object> createComponents(Client localClient, ClusterService cl
final XFFResolver xffResolver = new XFFResolver(threadPool);
backendRegistry = new BackendRegistry(settings, adminDns, xffResolver, auditLog, threadPool);

final CompatConfig compatConfig = new CompatConfig(environment);
final CompatConfig compatConfig = new CompatConfig(environment, transportPassiveAuthSetting);

// DLS-FLS is enabled if not client and not disabled and not SSL only.
final boolean dlsFlsEnabled = !SSLConfig.isSslOnlyMode();
Expand Down Expand Up @@ -813,7 +822,7 @@ public Collection<Object> createComponents(Client localClient, ClusterService cl
cr.setDynamicConfigFactory(dcf);

si = new SecurityInterceptor(settings, threadPool, backendRegistry, auditLog, principalExtractor,
interClusterRequestEvaluator, cs, Objects.requireNonNull(sslExceptionHandler), Objects.requireNonNull(cih));
interClusterRequestEvaluator, cs, Objects.requireNonNull(sslExceptionHandler), Objects.requireNonNull(cih), SSLConfig);
components.add(principalExtractor);

// NOTE: We need to create DefaultInterClusterRequestEvaluator before creating ConfigurationRepository since the latter requires security index to be accessible which means
Expand Down Expand Up @@ -990,6 +999,7 @@ public List<Setting<?>> getSettings() {
settings.add(Setting.listSetting(ConfigConstants.SECURITY_COMPLIANCE_IMMUTABLE_INDICES, Collections.emptyList(), Function.identity(), Property.NodeScope)); //not filtered here
settings.add(Setting.simpleString(ConfigConstants.SECURITY_COMPLIANCE_SALT, Property.NodeScope, Property.Filtered));
settings.add(Setting.boolSetting(ConfigConstants.SECURITY_COMPLIANCE_HISTORY_INTERNAL_CONFIG_ENABLED, false, Property.NodeScope, Property.Filtered));
settings.add(transportPassiveAuthSetting.getDynamicSetting());

settings.add(Setting.boolSetting(ConfigConstants.SECURITY_FILTER_SECURITYINDEX_FROM_ALL_REQUESTS, false, Property.NodeScope,
Property.Filtered));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

package org.opensearch.security.configuration;

import org.opensearch.security.setting.OpensearchDynamicSetting;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.opensearch.common.settings.Settings;
Expand All @@ -39,15 +40,19 @@
import org.opensearch.security.securityconf.DynamicConfigModel;
import org.opensearch.security.support.ConfigConstants;

import static org.opensearch.security.support.ConfigConstants.SECURITY_UNSUPPORTED_PASSIVE_INTERTRANSPORT_AUTH_INITIALLY;

public class CompatConfig {

private final Logger log = LogManager.getLogger(getClass());
private final Settings staticSettings;
private DynamicConfigModel dcm;
private final OpensearchDynamicSetting<Boolean> transportPassiveAuthSetting;

public CompatConfig(final Environment environment) {
public CompatConfig(final Environment environment, final OpensearchDynamicSetting<Boolean> transportPassiveAuthSetting) {
super();
this.staticSettings = environment.settings();
this.staticSettings = environment.settings();
this.transportPassiveAuthSetting = transportPassiveAuthSetting;
}

@Subscribe
Expand Down Expand Up @@ -100,4 +105,15 @@ public boolean transportInterClusterAuthEnabled() {
return true;
}
}

/**
* Returns true if passive transport auth is enabled
*/
public boolean transportInterClusterPassiveAuthEnabled() {
final boolean interClusterAuthInitiallyPassive = transportPassiveAuthSetting.getDynamicSettingValue();
if(log.isTraceEnabled()) {
log.trace("{} {}", SECURITY_UNSUPPORTED_PASSIVE_INTERTRANSPORT_AUTH_INITIALLY, interClusterAuthInitiallyPassive);
}
return interClusterAuthInitiallyPassive;
}
}
13 changes: 9 additions & 4 deletions src/main/java/org/opensearch/security/filter/SecurityFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -274,14 +274,19 @@ private <Request extends ActionRequest, Response extends ActionResponse> void ap
return;
}

boolean skipSecurityIfDualMode = threadContext.getTransient(ConfigConstants.SECURITY_SSL_DUAL_MODE_SKIP_SECURITY) == Boolean.TRUE;
if((interClusterRequest || trustedClusterRequest || request.remoteAddress() == null) && !compatConfig.transportInterClusterAuthEnabled()) {
chain.proceed(task, action, request, listener);
return;
} else if((interClusterRequest || trustedClusterRequest || request.remoteAddress() == null || skipSecurityIfDualMode) && compatConfig.transportInterClusterPassiveAuthEnabled()) {
log.info("Transport auth in passive mode and no user found. Injecting default user");
user = User.DEFAULT_TRANSPORT_USER;
threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_USER, user);
} else {
log.error("No user found for "+ action+" from "+request.remoteAddress()+" "+threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN)+" via "+threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_CHANNEL_TYPE)+" "+threadContext.getHeaders());
listener.onFailure(new OpenSearchSecurityException("No user found for "+action, RestStatus.INTERNAL_SERVER_ERROR));
return;
}

log.error("No user found for "+ action+" from "+request.remoteAddress()+" "+threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN)+" via "+threadContext.getTransient(ConfigConstants.OPENDISTRO_SECURITY_CHANNEL_TYPE)+" "+threadContext.getHeaders());
listener.onFailure(new OpenSearchSecurityException("No user found for "+action, RestStatus.INTERNAL_SERVER_ERROR));
return;
}

final PrivilegesEvaluator eval = evalp;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package org.opensearch.security.setting;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.opensearch.common.settings.ClusterSettings;
import org.opensearch.common.settings.Setting;

/**
* An abstract class to track the state of an opensearch dynamic setting.
* To instantiate for a dynamic setting, pass the Setting and the Setting's fetched value to the constructor
*
* @param <T> The type of the Setting
*/
public abstract class OpensearchDynamicSetting<T> {
private final Setting<T> dynamicSetting;
private volatile T dynamicSettingValue;

private final Logger logger = LogManager.getLogger(getClass());

public OpensearchDynamicSetting(Setting<T> dynamicSetting, T dynamicSettingValue) {
this.dynamicSetting = dynamicSetting;
this.dynamicSettingValue = dynamicSettingValue;
}

public void registerClusterSettingsChangeListener(final ClusterSettings clusterSettings) {
clusterSettings.addSettingsUpdateConsumer(dynamicSetting,
dynamicSettingNewValue -> {
logger.info(getClusterChangeMessage(dynamicSettingNewValue));
setDynamicSettingValue(dynamicSettingNewValue);
});
}

protected String getClusterChangeMessage(final T dynamicSettingNewValue) {
return String.format("Detected change in settings, updated cluster setting value is %s", dynamicSettingNewValue);
}

private void setDynamicSettingValue(final T dynamicSettingValue) {
this.dynamicSettingValue = dynamicSettingValue;
}

public T getDynamicSettingValue() {
return dynamicSettingValue;
}

public Setting<T> getDynamicSetting() {
return dynamicSetting;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package org.opensearch.security.setting;

import org.opensearch.security.support.ConfigConstants;
import org.opensearch.common.settings.Setting;
import org.opensearch.common.settings.Settings;

public class TransportPassiveAuthSetting extends OpensearchDynamicSetting<Boolean> {

private static final String SETTING = ConfigConstants.SECURITY_UNSUPPORTED_PASSIVE_INTERTRANSPORT_AUTH_INITIALLY;

public TransportPassiveAuthSetting(final Settings settings) {
super(getSetting(), getSettingInitialValue(settings));
}

private static Setting<Boolean> getSetting() {
return Setting.boolSetting(
SETTING,
false,
Setting.Property.NodeScope, Setting.Property.Dynamic);
}

private static Boolean getSettingInitialValue(final Settings settings) {
return settings.getAsBoolean(SETTING, false);
}

@Override
protected String getClusterChangeMessage(final Boolean dynamicSettingNewValue) {
return String.format("Detected change in settings, cluster setting for transportPassiveAuth is %s", dynamicSettingNewValue ? "enabled" : "disabled");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ public List<TransportInterceptor> getTransportInterceptors(NamedWriteableRegistr
List<TransportInterceptor> interceptors = new ArrayList<TransportInterceptor>(1);

if(transportSSLEnabled && !client) {
interceptors.add(new SecuritySSLTransportInterceptor(settings, null, null, NOOP_SSL_EXCEPTION_HANDLER));
interceptors.add(new SecuritySSLTransportInterceptor(settings, null, null, SSLConfig, NOOP_SSL_EXCEPTION_HANDLER));
}

return interceptors;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ public class SSLConfig {
public SSLConfig(final boolean sslOnly, final boolean dualModeEnabled) {
this.sslOnly = sslOnly;
this.dualModeEnabled = dualModeEnabled;
if (this.dualModeEnabled && !this.sslOnly) {
logger.warn("plugins.security_config.ssl_dual_mode_enabled is enabled but plugins.security.ssl_only mode is disabled. "
+ "SSL Dual mode is supported only when security plugin is in ssl_only mode");
}
logger.info("SSL dual mode is {}", isDualModeEnabled() ? "enabled" : "disabled");
}

Expand All @@ -58,8 +54,7 @@ private void setDualModeEnabled(boolean dualModeEnabled) {
}

public boolean isDualModeEnabled() {
// currently dual mode can be enabled only when SSLOnly is enabled. This stance can change in future.
return sslOnly && dualModeEnabled;
return dualModeEnabled;
}

public boolean isSslOnlyMode() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import javax.net.ssl.SSLPeerUnverifiedException;

import org.opensearch.security.support.ConfigConstants;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.opensearch.OpenSearchException;
Expand Down Expand Up @@ -54,22 +55,26 @@ public class SecuritySSLRequestHandler<T extends TransportRequest>
protected final Logger log = LogManager.getLogger(this.getClass());
private final PrincipalExtractor principalExtractor;
private final SslExceptionHandler errorHandler;
private final SSLConfig SSLConfig;

public SecuritySSLRequestHandler(String action, TransportRequestHandler<T> actualHandler,
ThreadPool threadPool, final PrincipalExtractor principalExtractor, final SslExceptionHandler errorHandler) {
ThreadPool threadPool, final PrincipalExtractor principalExtractor, final SSLConfig SSLConfig,
final SslExceptionHandler errorHandler) {

super();
this.action = action;
this.actualHandler = actualHandler;
this.threadPool = threadPool;
this.principalExtractor = principalExtractor;
this.SSLConfig = SSLConfig;
this.errorHandler = errorHandler;
}

protected ThreadContext getThreadContext() {
if(threadPool == null) {
return null;
}

return threadPool.getThreadContext();
}

Expand Down Expand Up @@ -111,6 +116,12 @@ public final void messageReceived(T request, TransportChannel channel, Task task
final SslHandler sslhandler = (SslHandler) nettyChannel.getNettyChannel().pipeline().get("ssl_server");

if (sslhandler == null) {
if (SSLConfig.isDualModeEnabled()) {
log.info("Communication in dual mode. Skipping SSL handler check");
threadContext.putTransient(ConfigConstants.SECURITY_SSL_DUAL_MODE_SKIP_SECURITY, Boolean.TRUE);
messageReceivedDecorate(request, actualHandler, channel, task);
return;
}
final String msg = "No ssl handler found (SG 11)";
//log.error(msg);
final Exception exception = new OpenSearchException(msg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,21 @@ public final class SecuritySSLTransportInterceptor implements TransportIntercept
protected final ThreadPool threadPool;
protected final PrincipalExtractor principalExtractor;
protected final SslExceptionHandler errorHandler;

protected final SSLConfig SSLConfig;

public SecuritySSLTransportInterceptor(final Settings settings, final ThreadPool threadPool,
PrincipalExtractor principalExtractor, final SslExceptionHandler errorHandler) {
PrincipalExtractor principalExtractor, final SSLConfig SSLConfig,
final SslExceptionHandler errorHandler) {
this.threadPool = threadPool;
this.principalExtractor = principalExtractor;
this.errorHandler = errorHandler;
this.SSLConfig = SSLConfig;
}

@Override
public <T extends TransportRequest> TransportRequestHandler<T> interceptHandler(String action, String executor, boolean forceExecution,
TransportRequestHandler<T> actualHandler) {
return new SecuritySSLRequestHandler<T>(action, actualHandler, threadPool, principalExtractor, errorHandler);
return new SecuritySSLRequestHandler<T>(action, actualHandler, threadPool, principalExtractor, SSLConfig, errorHandler);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ public class ConfigConstants {
public static final String SECURITY_COMPLIANCE_HISTORY_INTERNAL_CONFIG_ENABLED = "opendistro_security.compliance.history.internal_config_enabled";
public static final String SECURITY_SSL_ONLY = "plugins.security.ssl_only";
public static final String SECURITY_CONFIG_SSL_DUAL_MODE_ENABLED = "plugins.security_config.ssl_dual_mode_enabled";
public static final String SECURITY_SSL_DUAL_MODE_SKIP_SECURITY = OPENDISTRO_SECURITY_CONFIG_PREFIX+"passive_security";
public static final String LEGACY_OPENDISTRO_SECURITY_CONFIG_SSL_DUAL_MODE_ENABLED = "opendistro_security_config.ssl_dual_mode_enabled";
public static final String SECURITY_SSL_CERT_RELOAD_ENABLED = "plugins.security.ssl_cert_reload_enabled";
public static final String SECURITY_DISABLE_ENVVAR_REPLACEMENT = "plugins.security.disable_envvar_replacement";
Expand All @@ -245,6 +246,7 @@ public enum RolesMappingResolution {
// Illegal Opcodes from here on
public static final String SECURITY_UNSUPPORTED_DISABLE_REST_AUTH_INITIALLY = "plugins.security.unsupported.disable_rest_auth_initially";
public static final String SECURITY_UNSUPPORTED_DISABLE_INTERTRANSPORT_AUTH_INITIALLY = "plugins.security.unsupported.disable_intertransport_auth_initially";
public static final String SECURITY_UNSUPPORTED_PASSIVE_INTERTRANSPORT_AUTH_INITIALLY = "plugins.security.unsupported.passive_intertransport_auth_initially";
public static final String SECURITY_UNSUPPORTED_RESTORE_SECURITYINDEX_ENABLED = "plugins.security.unsupported.restore.securityindex.enabled";
public static final String SECURITY_UNSUPPORTED_INJECT_USER_ENABLED = "plugins.security.unsupported.inject_user.enabled";
public static final String SECURITY_UNSUPPORTED_INJECT_ADMIN_USER_ENABLED = "plugins.security.unsupported.inject_user.admin.enabled";
Expand Down
Loading

0 comments on commit ae628a5

Please sign in to comment.