Introduce ssl settings to reindex from remote (#37527)
Adds reindex.ssl.* settings for reindex from remote. This uses the ssl-config/ internal library to parse and load SSL configuration and files. This is applied when using the low level rest client to connect to a remote ES node Relates: #37287 Resolves: #29755
This commit is contained in:
parent
f5398d6511
commit
a8596de31f
|
@ -201,7 +201,7 @@ allprojects {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sets up the dependencies that we build as part of this project but
|
/* Sets up the dependencies that we build as part of this project but
|
||||||
register as thought they were external to resolve internally. We register
|
register as though they were external to resolve internally. We register
|
||||||
them as external dependencies so the build plugin that we use can be used
|
them as external dependencies so the build plugin that we use can be used
|
||||||
to build elasticsearch plugins outside of the elasticsearch source tree. */
|
to build elasticsearch plugins outside of the elasticsearch source tree. */
|
||||||
ext.projectSubstitutions = [
|
ext.projectSubstitutions = [
|
||||||
|
@ -214,6 +214,7 @@ allprojects {
|
||||||
"org.elasticsearch:elasticsearch-x-content:${version}": ':libs:x-content',
|
"org.elasticsearch:elasticsearch-x-content:${version}": ':libs:x-content',
|
||||||
"org.elasticsearch:elasticsearch-geo:${version}": ':libs:elasticsearch-geo',
|
"org.elasticsearch:elasticsearch-geo:${version}": ':libs:elasticsearch-geo',
|
||||||
"org.elasticsearch:elasticsearch-secure-sm:${version}": ':libs:secure-sm',
|
"org.elasticsearch:elasticsearch-secure-sm:${version}": ':libs:secure-sm',
|
||||||
|
"org.elasticsearch:elasticsearch-ssl-config:${version}": ':libs:elasticsearch-ssl-config',
|
||||||
"org.elasticsearch.client:elasticsearch-rest-client:${version}": ':client:rest',
|
"org.elasticsearch.client:elasticsearch-rest-client:${version}": ':client:rest',
|
||||||
"org.elasticsearch.client:elasticsearch-rest-client-sniffer:${version}": ':client:sniffer',
|
"org.elasticsearch.client:elasticsearch-rest-client-sniffer:${version}": ':client:sniffer',
|
||||||
"org.elasticsearch.client:elasticsearch-rest-high-level-client:${version}": ':client:rest-high-level',
|
"org.elasticsearch.client:elasticsearch-rest-high-level-client:${version}": ':client:rest-high-level',
|
||||||
|
|
|
@ -56,6 +56,7 @@ unitTest {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile "org.elasticsearch.client:elasticsearch-rest-client:${version}"
|
compile "org.elasticsearch.client:elasticsearch-rest-client:${version}"
|
||||||
|
compile "org.elasticsearch:elasticsearch-ssl-config:${version}"
|
||||||
// for http - testing reindex from remote
|
// for http - testing reindex from remote
|
||||||
testCompile project(path: ':modules:transport-netty4', configuration: 'runtime')
|
testCompile project(path: ':modules:transport-netty4', configuration: 'runtime')
|
||||||
// for parent/child testing
|
// for parent/child testing
|
||||||
|
@ -71,6 +72,11 @@ thirdPartyAudit.ignoreMissingClasses (
|
||||||
'org.apache.log.Logger',
|
'org.apache.log.Logger',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
forbiddenPatterns {
|
||||||
|
// PKCS#12 file are not UTF-8
|
||||||
|
exclude '**/*.p12'
|
||||||
|
}
|
||||||
|
|
||||||
// Support for testing reindex-from-remote against old Elaticsearch versions
|
// Support for testing reindex-from-remote against old Elaticsearch versions
|
||||||
configurations {
|
configurations {
|
||||||
oldesFixture
|
oldesFixture
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.elasticsearch.action.bulk.BulkResponse;
|
||||||
import org.elasticsearch.action.bulk.Retry;
|
import org.elasticsearch.action.bulk.Retry;
|
||||||
import org.elasticsearch.action.delete.DeleteRequest;
|
import org.elasticsearch.action.delete.DeleteRequest;
|
||||||
import org.elasticsearch.action.index.IndexRequest;
|
import org.elasticsearch.action.index.IndexRequest;
|
||||||
|
import org.elasticsearch.action.support.TransportAction;
|
||||||
import org.elasticsearch.client.ParentTaskAssigningClient;
|
import org.elasticsearch.client.ParentTaskAssigningClient;
|
||||||
import org.elasticsearch.common.unit.ByteSizeValue;
|
import org.elasticsearch.common.unit.ByteSizeValue;
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
|
@ -82,13 +83,15 @@ import static org.elasticsearch.search.sort.SortBuilders.fieldSort;
|
||||||
* Abstract base for scrolling across a search and executing bulk actions on all results. All package private methods are package private so
|
* Abstract base for scrolling across a search and executing bulk actions on all results. All package private methods are package private so
|
||||||
* their tests can use them. Most methods run in the listener thread pool because the are meant to be fast and don't expect to block.
|
* their tests can use them. Most methods run in the listener thread pool because the are meant to be fast and don't expect to block.
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractAsyncBulkByScrollAction<Request extends AbstractBulkByScrollRequest<Request>> {
|
public abstract class AbstractAsyncBulkByScrollAction<Request extends AbstractBulkByScrollRequest<Request>,
|
||||||
|
Action extends TransportAction<Request, ?>> {
|
||||||
|
|
||||||
protected final Logger logger;
|
protected final Logger logger;
|
||||||
protected final BulkByScrollTask task;
|
protected final BulkByScrollTask task;
|
||||||
protected final WorkerBulkByScrollTaskState worker;
|
protected final WorkerBulkByScrollTaskState worker;
|
||||||
protected final ThreadPool threadPool;
|
protected final ThreadPool threadPool;
|
||||||
protected final ScriptService scriptService;
|
|
||||||
|
|
||||||
|
protected final Action mainAction;
|
||||||
/**
|
/**
|
||||||
* The request for this action. Named mainRequest because we create lots of <code>request</code> variables all representing child
|
* The request for this action. Named mainRequest because we create lots of <code>request</code> variables all representing child
|
||||||
* requests of this mainRequest.
|
* requests of this mainRequest.
|
||||||
|
@ -112,7 +115,7 @@ public abstract class AbstractAsyncBulkByScrollAction<Request extends AbstractBu
|
||||||
|
|
||||||
public AbstractAsyncBulkByScrollAction(BulkByScrollTask task, boolean needsSourceDocumentVersions,
|
public AbstractAsyncBulkByScrollAction(BulkByScrollTask task, boolean needsSourceDocumentVersions,
|
||||||
boolean needsSourceDocumentSeqNoAndPrimaryTerm, Logger logger, ParentTaskAssigningClient client,
|
boolean needsSourceDocumentSeqNoAndPrimaryTerm, Logger logger, ParentTaskAssigningClient client,
|
||||||
ThreadPool threadPool, Request mainRequest, ScriptService scriptService,
|
ThreadPool threadPool, Action mainAction, Request mainRequest,
|
||||||
ActionListener<BulkByScrollResponse> listener) {
|
ActionListener<BulkByScrollResponse> listener) {
|
||||||
|
|
||||||
this.task = task;
|
this.task = task;
|
||||||
|
@ -124,7 +127,7 @@ public abstract class AbstractAsyncBulkByScrollAction<Request extends AbstractBu
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.threadPool = threadPool;
|
this.threadPool = threadPool;
|
||||||
this.scriptService = scriptService;
|
this.mainAction = mainAction;
|
||||||
this.mainRequest = mainRequest;
|
this.mainRequest = mainRequest;
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
BackoffPolicy backoffPolicy = buildBackoffPolicy();
|
BackoffPolicy backoffPolicy = buildBackoffPolicy();
|
||||||
|
|
|
@ -31,22 +31,22 @@ import org.elasticsearch.threadpool.ThreadPool;
|
||||||
/**
|
/**
|
||||||
* Implementation of delete-by-query using scrolling and bulk.
|
* Implementation of delete-by-query using scrolling and bulk.
|
||||||
*/
|
*/
|
||||||
public class AsyncDeleteByQueryAction extends AbstractAsyncBulkByScrollAction<DeleteByQueryRequest> {
|
public class AsyncDeleteByQueryAction extends AbstractAsyncBulkByScrollAction<DeleteByQueryRequest, TransportDeleteByQueryAction> {
|
||||||
|
|
||||||
private final boolean useSeqNoForCAS;
|
private final boolean useSeqNoForCAS;
|
||||||
|
|
||||||
public AsyncDeleteByQueryAction(BulkByScrollTask task, Logger logger, ParentTaskAssigningClient client,
|
public AsyncDeleteByQueryAction(BulkByScrollTask task, Logger logger, ParentTaskAssigningClient client,
|
||||||
ThreadPool threadPool, DeleteByQueryRequest request, ScriptService scriptService,
|
ThreadPool threadPool, TransportDeleteByQueryAction action, DeleteByQueryRequest request,
|
||||||
ClusterState clusterState, ActionListener<BulkByScrollResponse> listener) {
|
ScriptService scriptService, ClusterState clusterState, ActionListener<BulkByScrollResponse> listener) {
|
||||||
super(task,
|
super(task,
|
||||||
// not all nodes support sequence number powered optimistic concurrency control, we fall back to version
|
// not all nodes support sequence number powered optimistic concurrency control, we fall back to version
|
||||||
clusterState.nodes().getMinNodeVersion().onOrAfter(Version.V_6_7_0) == false,
|
clusterState.nodes().getMinNodeVersion().onOrAfter(Version.V_6_7_0) == false,
|
||||||
// all nodes support sequence number powered optimistic concurrency control and we can use it
|
// all nodes support sequence number powered optimistic concurrency control and we can use it
|
||||||
clusterState.nodes().getMinNodeVersion().onOrAfter(Version.V_6_7_0),
|
clusterState.nodes().getMinNodeVersion().onOrAfter(Version.V_6_7_0),
|
||||||
logger, client, threadPool, request, scriptService, listener);
|
logger, client, threadPool, action, request, listener);
|
||||||
useSeqNoForCAS = clusterState.nodes().getMinNodeVersion().onOrAfter(Version.V_6_7_0);
|
useSeqNoForCAS = clusterState.nodes().getMinNodeVersion().onOrAfter(Version.V_6_7_0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean accept(ScrollableHitSource.Hit doc) {
|
protected boolean accept(ScrollableHitSource.Hit doc) {
|
||||||
// Delete-by-query does not require the source to delete a document
|
// Delete-by-query does not require the source to delete a document
|
||||||
|
|
|
@ -21,21 +21,32 @@ package org.elasticsearch.index.reindex;
|
||||||
|
|
||||||
import org.elasticsearch.action.ActionRequest;
|
import org.elasticsearch.action.ActionRequest;
|
||||||
import org.elasticsearch.action.ActionResponse;
|
import org.elasticsearch.action.ActionResponse;
|
||||||
|
import org.elasticsearch.client.Client;
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||||
import org.elasticsearch.cluster.node.DiscoveryNodes;
|
import org.elasticsearch.cluster.node.DiscoveryNodes;
|
||||||
|
import org.elasticsearch.cluster.service.ClusterService;
|
||||||
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
|
||||||
import org.elasticsearch.common.settings.ClusterSettings;
|
import org.elasticsearch.common.settings.ClusterSettings;
|
||||||
import org.elasticsearch.common.settings.IndexScopedSettings;
|
import org.elasticsearch.common.settings.IndexScopedSettings;
|
||||||
import org.elasticsearch.common.settings.Setting;
|
import org.elasticsearch.common.settings.Setting;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.settings.SettingsFilter;
|
import org.elasticsearch.common.settings.SettingsFilter;
|
||||||
|
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
|
||||||
|
import org.elasticsearch.env.Environment;
|
||||||
|
import org.elasticsearch.env.NodeEnvironment;
|
||||||
import org.elasticsearch.plugins.ActionPlugin;
|
import org.elasticsearch.plugins.ActionPlugin;
|
||||||
import org.elasticsearch.plugins.Plugin;
|
import org.elasticsearch.plugins.Plugin;
|
||||||
import org.elasticsearch.rest.RestController;
|
import org.elasticsearch.rest.RestController;
|
||||||
import org.elasticsearch.rest.RestHandler;
|
import org.elasticsearch.rest.RestHandler;
|
||||||
|
import org.elasticsearch.script.ScriptService;
|
||||||
import org.elasticsearch.tasks.Task;
|
import org.elasticsearch.tasks.Task;
|
||||||
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
|
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
@ -69,8 +80,19 @@ public class ReindexPlugin extends Plugin implements ActionPlugin {
|
||||||
new RestRethrottleAction(settings, restController, nodesInCluster));
|
new RestRethrottleAction(settings, restController, nodesInCluster));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Object> createComponents(Client client, ClusterService clusterService, ThreadPool threadPool,
|
||||||
|
ResourceWatcherService resourceWatcherService, ScriptService scriptService,
|
||||||
|
NamedXContentRegistry xContentRegistry, Environment environment,
|
||||||
|
NodeEnvironment nodeEnvironment, NamedWriteableRegistry namedWriteableRegistry) {
|
||||||
|
return Collections.singletonList(new ReindexSslConfig(environment.settings(), environment, resourceWatcherService));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Setting<?>> getSettings() {
|
public List<Setting<?>> getSettings() {
|
||||||
return singletonList(TransportReindexAction.REMOTE_CLUSTER_WHITELIST);
|
final List<Setting<?>> settings = new ArrayList<>();
|
||||||
|
settings.add(TransportReindexAction.REMOTE_CLUSTER_WHITELIST);
|
||||||
|
settings.addAll(ReindexSslConfig.getSettings());
|
||||||
|
return settings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch licenses this file to you under
|
||||||
|
* the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License 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.elasticsearch.index.reindex;
|
||||||
|
|
||||||
|
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
|
||||||
|
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||||
|
import org.apache.http.nio.conn.ssl.SSLIOSessionStrategy;
|
||||||
|
import org.elasticsearch.common.Strings;
|
||||||
|
import org.elasticsearch.common.settings.SecureSetting;
|
||||||
|
import org.elasticsearch.common.settings.SecureString;
|
||||||
|
import org.elasticsearch.common.settings.Setting;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.ssl.SslConfiguration;
|
||||||
|
import org.elasticsearch.common.ssl.SslConfigurationKeys;
|
||||||
|
import org.elasticsearch.common.ssl.SslConfigurationLoader;
|
||||||
|
import org.elasticsearch.env.Environment;
|
||||||
|
import org.elasticsearch.watcher.FileChangesListener;
|
||||||
|
import org.elasticsearch.watcher.FileWatcher;
|
||||||
|
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||||
|
|
||||||
|
import javax.net.ssl.HostnameVerifier;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import static org.elasticsearch.common.settings.Setting.listSetting;
|
||||||
|
import static org.elasticsearch.common.settings.Setting.simpleString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads "reindex.ssl.*" configuration from Settings, and makes the applicable configuration (trust manager / key manager / hostname
|
||||||
|
* verification / cipher-suites) available for reindex-from-remote.
|
||||||
|
*/
|
||||||
|
class ReindexSslConfig {
|
||||||
|
|
||||||
|
private static final Map<String, Setting<?>> SETTINGS = new HashMap<>();
|
||||||
|
private static final Map<String, Setting<SecureString>> SECURE_SETTINGS = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
Setting.Property[] defaultProperties = new Setting.Property[] { Setting.Property.NodeScope, Setting.Property.Filtered };
|
||||||
|
Setting.Property[] deprecatedProperties = new Setting.Property[] { Setting.Property.Deprecated, Setting.Property.NodeScope,
|
||||||
|
Setting.Property.Filtered };
|
||||||
|
for (String key : SslConfigurationKeys.getStringKeys()) {
|
||||||
|
String settingName = "reindex.ssl." + key;
|
||||||
|
final Setting.Property[] properties = SslConfigurationKeys.isDeprecated(key) ? deprecatedProperties : defaultProperties;
|
||||||
|
SETTINGS.put(settingName, simpleString(settingName, properties));
|
||||||
|
}
|
||||||
|
for (String key : SslConfigurationKeys.getListKeys()) {
|
||||||
|
String settingName = "reindex.ssl." + key;
|
||||||
|
final Setting.Property[] properties = SslConfigurationKeys.isDeprecated(key) ? deprecatedProperties : defaultProperties;
|
||||||
|
SETTINGS.put(settingName, listSetting(settingName, Collections.emptyList(), Function.identity(), properties));
|
||||||
|
}
|
||||||
|
for (String key : SslConfigurationKeys.getSecureStringKeys()) {
|
||||||
|
String settingName = "reindex.ssl." + key;
|
||||||
|
SECURE_SETTINGS.put(settingName, SecureSetting.secureString(settingName, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final SslConfiguration configuration;
|
||||||
|
private volatile SSLContext context;
|
||||||
|
|
||||||
|
public static List<Setting<?>> getSettings() {
|
||||||
|
List<Setting<?>> settings = new ArrayList<>();
|
||||||
|
settings.addAll(SETTINGS.values());
|
||||||
|
settings.addAll(SECURE_SETTINGS.values());
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReindexSslConfig(Settings settings, Environment environment, ResourceWatcherService resourceWatcher) {
|
||||||
|
final SslConfigurationLoader loader = new SslConfigurationLoader("reindex.ssl.") {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getSettingAsString(String key) {
|
||||||
|
return settings.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected char[] getSecureSetting(String key) {
|
||||||
|
final Setting<SecureString> setting = SECURE_SETTINGS.get(key);
|
||||||
|
if (setting == null) {
|
||||||
|
throw new IllegalArgumentException("The secure setting [" + key + "] is not registered");
|
||||||
|
}
|
||||||
|
return setting.get(settings).getChars();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> getSettingAsList(String key) throws Exception {
|
||||||
|
return settings.getAsList(key);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
configuration = loader.load(environment.configFile());
|
||||||
|
reload();
|
||||||
|
|
||||||
|
final FileChangesListener listener = new FileChangesListener() {
|
||||||
|
@Override
|
||||||
|
public void onFileCreated(Path file) {
|
||||||
|
onFileChanged(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFileDeleted(Path file) {
|
||||||
|
onFileChanged(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFileChanged(Path file) {
|
||||||
|
ReindexSslConfig.this.reload();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (Path file : configuration.getDependentFiles()) {
|
||||||
|
try {
|
||||||
|
final FileWatcher watcher = new FileWatcher(file);
|
||||||
|
watcher.addListener(listener);
|
||||||
|
resourceWatcher.add(watcher, ResourceWatcherService.Frequency.HIGH);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new UncheckedIOException("cannot watch file [" + file + "]", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reload() {
|
||||||
|
this.context = configuration.createSslContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulate the loaded SSL configuration as a HTTP-client {@link SSLIOSessionStrategy}.
|
||||||
|
* The returned strategy is immutable, but successive calls will return different objects that may have different
|
||||||
|
* configurations if the underlying key/certificate files are modified.
|
||||||
|
*/
|
||||||
|
SSLIOSessionStrategy getStrategy() {
|
||||||
|
final HostnameVerifier hostnameVerifier = configuration.getVerificationMode().isHostnameVerificationEnabled()
|
||||||
|
? new DefaultHostnameVerifier()
|
||||||
|
: new NoopHostnameVerifier();
|
||||||
|
final String[] protocols = configuration.getSupportedProtocols().toArray(Strings.EMPTY_ARRAY);
|
||||||
|
final String[] cipherSuites = configuration.getCipherSuites().toArray(Strings.EMPTY_ARRAY);
|
||||||
|
return new SSLIOSessionStrategy(context, protocols, cipherSuites, hostnameVerifier);
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,7 +61,7 @@ public class TransportDeleteByQueryAction extends HandledTransportAction<DeleteB
|
||||||
ClusterState state = clusterService.state();
|
ClusterState state = clusterService.state();
|
||||||
ParentTaskAssigningClient assigningClient = new ParentTaskAssigningClient(client, clusterService.localNode(),
|
ParentTaskAssigningClient assigningClient = new ParentTaskAssigningClient(client, clusterService.localNode(),
|
||||||
bulkByScrollTask);
|
bulkByScrollTask);
|
||||||
new AsyncDeleteByQueryAction(bulkByScrollTask, logger, assigningClient, threadPool, request, scriptService, state,
|
new AsyncDeleteByQueryAction(bulkByScrollTask, logger, assigningClient, threadPool, this, request, scriptService, state,
|
||||||
listener).start();
|
listener).start();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -101,10 +101,12 @@ public class TransportReindexAction extends HandledTransportAction<ReindexReques
|
||||||
private final CharacterRunAutomaton remoteWhitelist;
|
private final CharacterRunAutomaton remoteWhitelist;
|
||||||
private final IndexNameExpressionResolver indexNameExpressionResolver;
|
private final IndexNameExpressionResolver indexNameExpressionResolver;
|
||||||
|
|
||||||
|
private final ReindexSslConfig sslConfig;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public TransportReindexAction(Settings settings, ThreadPool threadPool, ActionFilters actionFilters,
|
public TransportReindexAction(Settings settings, ThreadPool threadPool, ActionFilters actionFilters,
|
||||||
IndexNameExpressionResolver indexNameExpressionResolver, ClusterService clusterService, ScriptService scriptService,
|
IndexNameExpressionResolver indexNameExpressionResolver, ClusterService clusterService, ScriptService scriptService,
|
||||||
AutoCreateIndex autoCreateIndex, Client client, TransportService transportService) {
|
AutoCreateIndex autoCreateIndex, Client client, TransportService transportService, ReindexSslConfig sslConfig) {
|
||||||
super(ReindexAction.NAME, transportService, actionFilters, (Writeable.Reader<ReindexRequest>)ReindexRequest::new);
|
super(ReindexAction.NAME, transportService, actionFilters, (Writeable.Reader<ReindexRequest>)ReindexRequest::new);
|
||||||
this.threadPool = threadPool;
|
this.threadPool = threadPool;
|
||||||
this.clusterService = clusterService;
|
this.clusterService = clusterService;
|
||||||
|
@ -113,6 +115,7 @@ public class TransportReindexAction extends HandledTransportAction<ReindexReques
|
||||||
this.client = client;
|
this.client = client;
|
||||||
remoteWhitelist = buildRemoteWhitelist(REMOTE_CLUSTER_WHITELIST.get(settings));
|
remoteWhitelist = buildRemoteWhitelist(REMOTE_CLUSTER_WHITELIST.get(settings));
|
||||||
this.indexNameExpressionResolver = indexNameExpressionResolver;
|
this.indexNameExpressionResolver = indexNameExpressionResolver;
|
||||||
|
this.sslConfig = sslConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -129,7 +132,7 @@ public class TransportReindexAction extends HandledTransportAction<ReindexReques
|
||||||
() -> {
|
() -> {
|
||||||
ParentTaskAssigningClient assigningClient = new ParentTaskAssigningClient(client, clusterService.localNode(),
|
ParentTaskAssigningClient assigningClient = new ParentTaskAssigningClient(client, clusterService.localNode(),
|
||||||
bulkByScrollTask);
|
bulkByScrollTask);
|
||||||
new AsyncIndexBySearchAction(bulkByScrollTask, logger, assigningClient, threadPool, request, scriptService, state,
|
new AsyncIndexBySearchAction(bulkByScrollTask, logger, assigningClient, threadPool, this, request, state,
|
||||||
listener).start();
|
listener).start();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -197,10 +200,11 @@ public class TransportReindexAction extends HandledTransportAction<ReindexReques
|
||||||
/**
|
/**
|
||||||
* Build the {@link RestClient} used for reindexing from remote clusters.
|
* Build the {@link RestClient} used for reindexing from remote clusters.
|
||||||
* @param remoteInfo connection information for the remote cluster
|
* @param remoteInfo connection information for the remote cluster
|
||||||
|
* @param sslConfig configuration for potential outgoing HTTPS connections
|
||||||
* @param taskId the id of the current task. This is added to the thread name for easier tracking
|
* @param taskId the id of the current task. This is added to the thread name for easier tracking
|
||||||
* @param threadCollector a list in which we collect all the threads created by the client
|
* @param threadCollector a list in which we collect all the threads created by the client
|
||||||
*/
|
*/
|
||||||
static RestClient buildRestClient(RemoteInfo remoteInfo, long taskId, List<Thread> threadCollector) {
|
static RestClient buildRestClient(RemoteInfo remoteInfo, ReindexSslConfig sslConfig, long taskId, List<Thread> threadCollector) {
|
||||||
Header[] clientHeaders = new Header[remoteInfo.getHeaders().size()];
|
Header[] clientHeaders = new Header[remoteInfo.getHeaders().size()];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (Map.Entry<String, String> header : remoteInfo.getHeaders().entrySet()) {
|
for (Map.Entry<String, String> header : remoteInfo.getHeaders().entrySet()) {
|
||||||
|
@ -233,6 +237,7 @@ public class TransportReindexAction extends HandledTransportAction<ReindexReques
|
||||||
});
|
});
|
||||||
// Limit ourselves to one reactor thread because for now the search process is single threaded.
|
// Limit ourselves to one reactor thread because for now the search process is single threaded.
|
||||||
c.setDefaultIOReactorConfig(IOReactorConfig.custom().setIoThreadCount(1).build());
|
c.setDefaultIOReactorConfig(IOReactorConfig.custom().setIoThreadCount(1).build());
|
||||||
|
c.setSSLStrategy(sslConfig.getStrategy());
|
||||||
return c;
|
return c;
|
||||||
});
|
});
|
||||||
if (Strings.hasLength(remoteInfo.getPathPrefix()) && "/".equals(remoteInfo.getPathPrefix()) == false) {
|
if (Strings.hasLength(remoteInfo.getPathPrefix()) && "/".equals(remoteInfo.getPathPrefix()) == false) {
|
||||||
|
@ -247,7 +252,7 @@ public class TransportReindexAction extends HandledTransportAction<ReindexReques
|
||||||
* but this makes no attempt to do any of them so it can be as simple
|
* but this makes no attempt to do any of them so it can be as simple
|
||||||
* possible.
|
* possible.
|
||||||
*/
|
*/
|
||||||
static class AsyncIndexBySearchAction extends AbstractAsyncBulkByScrollAction<ReindexRequest> {
|
static class AsyncIndexBySearchAction extends AbstractAsyncBulkByScrollAction<ReindexRequest, TransportReindexAction> {
|
||||||
/**
|
/**
|
||||||
* List of threads created by this process. Usually actions don't create threads in Elasticsearch. Instead they use the builtin
|
* List of threads created by this process. Usually actions don't create threads in Elasticsearch. Instead they use the builtin
|
||||||
* {@link ThreadPool}s. But reindex-from-remote uses Elasticsearch's {@link RestClient} which doesn't use the
|
* {@link ThreadPool}s. But reindex-from-remote uses Elasticsearch's {@link RestClient} which doesn't use the
|
||||||
|
@ -257,7 +262,7 @@ public class TransportReindexAction extends HandledTransportAction<ReindexReques
|
||||||
private List<Thread> createdThreads = emptyList();
|
private List<Thread> createdThreads = emptyList();
|
||||||
|
|
||||||
AsyncIndexBySearchAction(BulkByScrollTask task, Logger logger, ParentTaskAssigningClient client,
|
AsyncIndexBySearchAction(BulkByScrollTask task, Logger logger, ParentTaskAssigningClient client,
|
||||||
ThreadPool threadPool, ReindexRequest request, ScriptService scriptService, ClusterState clusterState,
|
ThreadPool threadPool, TransportReindexAction action, ReindexRequest request, ClusterState clusterState,
|
||||||
ActionListener<BulkByScrollResponse> listener) {
|
ActionListener<BulkByScrollResponse> listener) {
|
||||||
super(task,
|
super(task,
|
||||||
/*
|
/*
|
||||||
|
@ -265,7 +270,7 @@ public class TransportReindexAction extends HandledTransportAction<ReindexReques
|
||||||
* external versioning.
|
* external versioning.
|
||||||
*/
|
*/
|
||||||
request.getDestination().versionType() != VersionType.INTERNAL,
|
request.getDestination().versionType() != VersionType.INTERNAL,
|
||||||
false, logger, client, threadPool, request, scriptService, listener);
|
false, logger, client, threadPool, action, request, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -273,7 +278,7 @@ public class TransportReindexAction extends HandledTransportAction<ReindexReques
|
||||||
if (mainRequest.getRemoteInfo() != null) {
|
if (mainRequest.getRemoteInfo() != null) {
|
||||||
RemoteInfo remoteInfo = mainRequest.getRemoteInfo();
|
RemoteInfo remoteInfo = mainRequest.getRemoteInfo();
|
||||||
createdThreads = synchronizedList(new ArrayList<>());
|
createdThreads = synchronizedList(new ArrayList<>());
|
||||||
RestClient restClient = buildRestClient(remoteInfo, task.getId(), createdThreads);
|
RestClient restClient = buildRestClient(remoteInfo, mainAction.sslConfig, task.getId(), createdThreads);
|
||||||
return new RemoteScrollableHitSource(logger, backoffPolicy, threadPool, worker::countSearchRetry, this::finishHim,
|
return new RemoteScrollableHitSource(logger, backoffPolicy, threadPool, worker::countSearchRetry, this::finishHim,
|
||||||
restClient, remoteInfo.getQuery(), mainRequest.getSearchRequest());
|
restClient, remoteInfo.getQuery(), mainRequest.getSearchRequest());
|
||||||
}
|
}
|
||||||
|
@ -296,7 +301,7 @@ public class TransportReindexAction extends HandledTransportAction<ReindexReques
|
||||||
public BiFunction<RequestWrapper<?>, ScrollableHitSource.Hit, RequestWrapper<?>> buildScriptApplier() {
|
public BiFunction<RequestWrapper<?>, ScrollableHitSource.Hit, RequestWrapper<?>> buildScriptApplier() {
|
||||||
Script script = mainRequest.getScript();
|
Script script = mainRequest.getScript();
|
||||||
if (script != null) {
|
if (script != null) {
|
||||||
return new ReindexScriptApplier(worker, scriptService, script, script.getParams());
|
return new ReindexScriptApplier(worker, mainAction.scriptService, script, script.getParams());
|
||||||
}
|
}
|
||||||
return super.buildScriptApplier();
|
return super.buildScriptApplier();
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ public class TransportUpdateByQueryAction extends HandledTransportAction<UpdateB
|
||||||
ClusterState state = clusterService.state();
|
ClusterState state = clusterService.state();
|
||||||
ParentTaskAssigningClient assigningClient = new ParentTaskAssigningClient(client, clusterService.localNode(),
|
ParentTaskAssigningClient assigningClient = new ParentTaskAssigningClient(client, clusterService.localNode(),
|
||||||
bulkByScrollTask);
|
bulkByScrollTask);
|
||||||
new AsyncIndexBySearchAction(bulkByScrollTask, logger, assigningClient, threadPool, request, scriptService, state,
|
new AsyncIndexBySearchAction(bulkByScrollTask, logger, assigningClient, threadPool, this, request, state,
|
||||||
listener).start();
|
listener).start();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -81,19 +81,19 @@ public class TransportUpdateByQueryAction extends HandledTransportAction<UpdateB
|
||||||
/**
|
/**
|
||||||
* Simple implementation of update-by-query using scrolling and bulk.
|
* Simple implementation of update-by-query using scrolling and bulk.
|
||||||
*/
|
*/
|
||||||
static class AsyncIndexBySearchAction extends AbstractAsyncBulkByScrollAction<UpdateByQueryRequest> {
|
static class AsyncIndexBySearchAction extends AbstractAsyncBulkByScrollAction<UpdateByQueryRequest, TransportUpdateByQueryAction> {
|
||||||
|
|
||||||
private final boolean useSeqNoForCAS;
|
private final boolean useSeqNoForCAS;
|
||||||
|
|
||||||
AsyncIndexBySearchAction(BulkByScrollTask task, Logger logger, ParentTaskAssigningClient client,
|
AsyncIndexBySearchAction(BulkByScrollTask task, Logger logger, ParentTaskAssigningClient client,
|
||||||
ThreadPool threadPool, UpdateByQueryRequest request, ScriptService scriptService, ClusterState clusterState,
|
ThreadPool threadPool, TransportUpdateByQueryAction action, UpdateByQueryRequest request, ClusterState clusterState,
|
||||||
ActionListener<BulkByScrollResponse> listener) {
|
ActionListener<BulkByScrollResponse> listener) {
|
||||||
super(task,
|
super(task,
|
||||||
// not all nodes support sequence number powered optimistic concurrency control, we fall back to version
|
// not all nodes support sequence number powered optimistic concurrency control, we fall back to version
|
||||||
clusterState.nodes().getMinNodeVersion().onOrAfter(Version.V_6_7_0) == false,
|
clusterState.nodes().getMinNodeVersion().onOrAfter(Version.V_6_7_0) == false,
|
||||||
// all nodes support sequence number powered optimistic concurrency control and we can use it
|
// all nodes support sequence number powered optimistic concurrency control and we can use it
|
||||||
clusterState.nodes().getMinNodeVersion().onOrAfter(Version.V_6_7_0),
|
clusterState.nodes().getMinNodeVersion().onOrAfter(Version.V_6_7_0),
|
||||||
logger, client, threadPool, request, scriptService, listener);
|
logger, client, threadPool, action, request, listener);
|
||||||
useSeqNoForCAS = clusterState.nodes().getMinNodeVersion().onOrAfter(Version.V_6_7_0);
|
useSeqNoForCAS = clusterState.nodes().getMinNodeVersion().onOrAfter(Version.V_6_7_0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ public class TransportUpdateByQueryAction extends HandledTransportAction<UpdateB
|
||||||
public BiFunction<RequestWrapper<?>, ScrollableHitSource.Hit, RequestWrapper<?>> buildScriptApplier() {
|
public BiFunction<RequestWrapper<?>, ScrollableHitSource.Hit, RequestWrapper<?>> buildScriptApplier() {
|
||||||
Script script = mainRequest.getScript();
|
Script script = mainRequest.getScript();
|
||||||
if (script != null) {
|
if (script != null) {
|
||||||
return new UpdateByQueryScriptApplier(worker, scriptService, script, script.getParams());
|
return new UpdateByQueryScriptApplier(worker, mainAction.scriptService, script, script.getParams());
|
||||||
}
|
}
|
||||||
return super.buildScriptApplier();
|
return super.buildScriptApplier();
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,5 +28,5 @@ public abstract class AbstractAsyncBulkByScrollActionMetadataTestCase<
|
||||||
return new ScrollableHitSource.BasicHit("index", "type", "id", 0);
|
return new ScrollableHitSource.BasicHit("index", "type", "id", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract AbstractAsyncBulkByScrollAction<Request> action();
|
protected abstract AbstractAsyncBulkByScrollAction<Request, ?> action();
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ public abstract class AbstractAsyncBulkByScrollActionScriptTestCase<
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
when(scriptService.compile(any(), eq(UpdateScript.CONTEXT))).thenReturn(factory);
|
when(scriptService.compile(any(), eq(UpdateScript.CONTEXT))).thenReturn(factory);
|
||||||
AbstractAsyncBulkByScrollAction<Request> action = action(scriptService, request().setScript(mockScript("")));
|
AbstractAsyncBulkByScrollAction<Request, ?> action = action(scriptService, request().setScript(mockScript("")));
|
||||||
RequestWrapper<?> result = action.buildScriptApplier().apply(AbstractAsyncBulkByScrollAction.wrap(index), doc);
|
RequestWrapper<?> result = action.buildScriptApplier().apply(AbstractAsyncBulkByScrollAction.wrap(index), doc);
|
||||||
return (result != null) ? (T) result.self() : null;
|
return (result != null) ? (T) result.self() : null;
|
||||||
}
|
}
|
||||||
|
@ -109,5 +109,5 @@ public abstract class AbstractAsyncBulkByScrollActionScriptTestCase<
|
||||||
assertThat(e.getMessage(), equalTo("Operation type [unknown] not allowed, only [noop, index, delete] are allowed"));
|
assertThat(e.getMessage(), equalTo("Operation type [unknown] not allowed, only [noop, index, delete] are allowed"));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract AbstractAsyncBulkByScrollAction<Request> action(ScriptService scriptService, Request request);
|
protected abstract AbstractAsyncBulkByScrollAction<Request, ?> action(ScriptService scriptService, Request request);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,9 @@ import org.elasticsearch.action.search.SearchRequest;
|
||||||
import org.elasticsearch.action.search.SearchResponse;
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
import org.elasticsearch.action.search.SearchScrollRequest;
|
import org.elasticsearch.action.search.SearchScrollRequest;
|
||||||
import org.elasticsearch.action.search.ShardSearchFailure;
|
import org.elasticsearch.action.search.ShardSearchFailure;
|
||||||
|
import org.elasticsearch.action.support.ActionFilters;
|
||||||
import org.elasticsearch.action.support.PlainActionFuture;
|
import org.elasticsearch.action.support.PlainActionFuture;
|
||||||
|
import org.elasticsearch.action.support.TransportAction;
|
||||||
import org.elasticsearch.action.update.UpdateRequest;
|
import org.elasticsearch.action.update.UpdateRequest;
|
||||||
import org.elasticsearch.action.update.UpdateResponse;
|
import org.elasticsearch.action.update.UpdateResponse;
|
||||||
import org.elasticsearch.client.Client;
|
import org.elasticsearch.client.Client;
|
||||||
|
@ -71,6 +73,7 @@ import org.elasticsearch.rest.RestStatus;
|
||||||
import org.elasticsearch.search.SearchHit;
|
import org.elasticsearch.search.SearchHit;
|
||||||
import org.elasticsearch.search.SearchHits;
|
import org.elasticsearch.search.SearchHits;
|
||||||
import org.elasticsearch.search.internal.InternalSearchResponse;
|
import org.elasticsearch.search.internal.InternalSearchResponse;
|
||||||
|
import org.elasticsearch.tasks.Task;
|
||||||
import org.elasticsearch.tasks.TaskId;
|
import org.elasticsearch.tasks.TaskId;
|
||||||
import org.elasticsearch.tasks.TaskManager;
|
import org.elasticsearch.tasks.TaskManager;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
@ -675,10 +678,11 @@ public class AsyncBulkByScrollActionTests extends ESTestCase {
|
||||||
action.onScrollResponse(lastBatchTime, lastBatchSize, response);
|
action.onScrollResponse(lastBatchTime, lastBatchSize, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DummyAsyncBulkByScrollAction extends AbstractAsyncBulkByScrollAction<DummyAbstractBulkByScrollRequest> {
|
private class DummyAsyncBulkByScrollAction
|
||||||
|
extends AbstractAsyncBulkByScrollAction<DummyAbstractBulkByScrollRequest, DummyTransportAsyncBulkByScrollAction> {
|
||||||
DummyAsyncBulkByScrollAction() {
|
DummyAsyncBulkByScrollAction() {
|
||||||
super(testTask, randomBoolean(), randomBoolean(), AsyncBulkByScrollActionTests.this.logger,
|
super(testTask, randomBoolean(), randomBoolean(), AsyncBulkByScrollActionTests.this.logger,
|
||||||
new ParentTaskAssigningClient(client, localNode, testTask), client.threadPool(), testRequest, null, listener);
|
new ParentTaskAssigningClient(client, localNode, testTask), client.threadPool(), null, testRequest, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -698,6 +702,20 @@ public class AsyncBulkByScrollActionTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class DummyTransportAsyncBulkByScrollAction
|
||||||
|
extends TransportAction<DummyAbstractBulkByScrollRequest, BulkByScrollResponse> {
|
||||||
|
|
||||||
|
|
||||||
|
protected DummyTransportAsyncBulkByScrollAction(String actionName, ActionFilters actionFilters, TaskManager taskManager) {
|
||||||
|
super(actionName, actionFilters, taskManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doExecute(Task task, DummyAbstractBulkByScrollRequest request, ActionListener<BulkByScrollResponse> listener) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class DummyAbstractBulkByScrollRequest extends AbstractBulkByScrollRequest<DummyAbstractBulkByScrollRequest> {
|
private static class DummyAbstractBulkByScrollRequest extends AbstractBulkByScrollRequest<DummyAbstractBulkByScrollRequest> {
|
||||||
DummyAbstractBulkByScrollRequest(SearchRequest searchRequest) {
|
DummyAbstractBulkByScrollRequest(SearchRequest searchRequest) {
|
||||||
super(searchRequest, true);
|
super(searchRequest, true);
|
||||||
|
|
|
@ -22,6 +22,10 @@ package org.elasticsearch.index.reindex;
|
||||||
import org.elasticsearch.client.RestClient;
|
import org.elasticsearch.client.RestClient;
|
||||||
import org.elasticsearch.client.RestClientBuilderTestCase;
|
import org.elasticsearch.client.RestClientBuilderTestCase;
|
||||||
import org.elasticsearch.common.bytes.BytesArray;
|
import org.elasticsearch.common.bytes.BytesArray;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.env.Environment;
|
||||||
|
import org.elasticsearch.env.TestEnvironment;
|
||||||
|
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -31,6 +35,7 @@ import java.util.Map;
|
||||||
import static java.util.Collections.emptyMap;
|
import static java.util.Collections.emptyMap;
|
||||||
import static java.util.Collections.synchronizedList;
|
import static java.util.Collections.synchronizedList;
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
public class ReindexFromRemoteBuildRestClientTests extends RestClientBuilderTestCase {
|
public class ReindexFromRemoteBuildRestClientTests extends RestClientBuilderTestCase {
|
||||||
public void testBuildRestClient() throws Exception {
|
public void testBuildRestClient() throws Exception {
|
||||||
|
@ -39,7 +44,7 @@ public class ReindexFromRemoteBuildRestClientTests extends RestClientBuilderTest
|
||||||
RemoteInfo.DEFAULT_SOCKET_TIMEOUT, RemoteInfo.DEFAULT_CONNECT_TIMEOUT);
|
RemoteInfo.DEFAULT_SOCKET_TIMEOUT, RemoteInfo.DEFAULT_CONNECT_TIMEOUT);
|
||||||
long taskId = randomLong();
|
long taskId = randomLong();
|
||||||
List<Thread> threads = synchronizedList(new ArrayList<>());
|
List<Thread> threads = synchronizedList(new ArrayList<>());
|
||||||
RestClient client = TransportReindexAction.buildRestClient(remoteInfo, taskId, threads);
|
RestClient client = TransportReindexAction.buildRestClient(remoteInfo, sslConfig(), taskId, threads);
|
||||||
try {
|
try {
|
||||||
assertBusy(() -> assertThat(threads, hasSize(2)));
|
assertBusy(() -> assertThat(threads, hasSize(2)));
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -63,11 +68,18 @@ public class ReindexFromRemoteBuildRestClientTests extends RestClientBuilderTest
|
||||||
headers, RemoteInfo.DEFAULT_SOCKET_TIMEOUT, RemoteInfo.DEFAULT_CONNECT_TIMEOUT);
|
headers, RemoteInfo.DEFAULT_SOCKET_TIMEOUT, RemoteInfo.DEFAULT_CONNECT_TIMEOUT);
|
||||||
long taskId = randomLong();
|
long taskId = randomLong();
|
||||||
List<Thread> threads = synchronizedList(new ArrayList<>());
|
List<Thread> threads = synchronizedList(new ArrayList<>());
|
||||||
RestClient client = TransportReindexAction.buildRestClient(remoteInfo, taskId, threads);
|
RestClient client = TransportReindexAction.buildRestClient(remoteInfo, sslConfig(), taskId, threads);
|
||||||
try {
|
try {
|
||||||
assertHeaders(client, headers);
|
assertHeaders(client, headers);
|
||||||
} finally {
|
} finally {
|
||||||
client.close();
|
client.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ReindexSslConfig sslConfig() {
|
||||||
|
final Environment environment = TestEnvironment.newEnvironment(Settings.builder().put("path.home", createTempDir()).build());
|
||||||
|
final ResourceWatcherService resourceWatcher = mock(ResourceWatcherService.class);
|
||||||
|
return new ReindexSslConfig(environment.settings(), environment, resourceWatcher);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,8 +76,8 @@ public class ReindexMetadataTests extends AbstractAsyncBulkByScrollActionMetadat
|
||||||
|
|
||||||
private class TestAction extends TransportReindexAction.AsyncIndexBySearchAction {
|
private class TestAction extends TransportReindexAction.AsyncIndexBySearchAction {
|
||||||
TestAction() {
|
TestAction() {
|
||||||
super(ReindexMetadataTests.this.task, ReindexMetadataTests.this.logger, null, ReindexMetadataTests.this.threadPool, request(),
|
super(ReindexMetadataTests.this.task, ReindexMetadataTests.this.logger, null, ReindexMetadataTests.this.threadPool,
|
||||||
null, null, listener());
|
null, request(), null, listener());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReindexRequest mainRequest() {
|
public ReindexRequest mainRequest() {
|
||||||
|
|
|
@ -0,0 +1,213 @@
|
||||||
|
/*
|
||||||
|
* Licensed to Elasticsearch under one or more contributor
|
||||||
|
* license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright
|
||||||
|
* ownership. Elasticsearch licenses this file to you under
|
||||||
|
* the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
* not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License 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.elasticsearch.index.reindex;
|
||||||
|
|
||||||
|
import com.sun.net.httpserver.HttpsConfigurator;
|
||||||
|
import com.sun.net.httpserver.HttpsExchange;
|
||||||
|
import com.sun.net.httpserver.HttpsParameters;
|
||||||
|
import com.sun.net.httpserver.HttpsServer;
|
||||||
|
import org.elasticsearch.client.Request;
|
||||||
|
import org.elasticsearch.client.Response;
|
||||||
|
import org.elasticsearch.client.RestClient;
|
||||||
|
import org.elasticsearch.common.SuppressForbidden;
|
||||||
|
import org.elasticsearch.common.bytes.BytesArray;
|
||||||
|
import org.elasticsearch.common.io.PathUtils;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.ssl.PemKeyConfig;
|
||||||
|
import org.elasticsearch.common.ssl.PemTrustConfig;
|
||||||
|
import org.elasticsearch.env.Environment;
|
||||||
|
import org.elasticsearch.env.TestEnvironment;
|
||||||
|
import org.elasticsearch.mocksocket.MockHttpServer;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||||
|
import org.hamcrest.Matchers;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
|
||||||
|
import javax.net.ssl.KeyManager;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLHandshakeException;
|
||||||
|
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||||
|
import javax.net.ssl.TrustManager;
|
||||||
|
import javax.net.ssl.X509ExtendedKeyManager;
|
||||||
|
import javax.net.ssl.X509ExtendedTrustManager;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Because core ES doesn't have SSL available, this test uses a mock webserver
|
||||||
|
* as the remote endpoint.
|
||||||
|
* This makes it hard to test actual reindex functionality, but does allow us to test that the correct connections are made with the
|
||||||
|
* right SSL keys + trust settings.
|
||||||
|
*/
|
||||||
|
@SuppressForbidden(reason = "use http server")
|
||||||
|
public class ReindexRestClientSslTests extends ESTestCase {
|
||||||
|
|
||||||
|
private static HttpsServer server;
|
||||||
|
private static Consumer<HttpsExchange> handler = ignore -> {
|
||||||
|
};
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setupHttpServer() throws Exception {
|
||||||
|
InetSocketAddress address = new InetSocketAddress(InetAddress.getLoopbackAddress().getHostAddress(), 0);
|
||||||
|
SSLContext sslContext = buildServerSslContext();
|
||||||
|
server = MockHttpServer.createHttps(address, 0);
|
||||||
|
server.setHttpsConfigurator(new ClientAuthHttpsConfigurator(sslContext));
|
||||||
|
server.start();
|
||||||
|
server.createContext("/", http -> {
|
||||||
|
assert http instanceof HttpsExchange;
|
||||||
|
HttpsExchange https = (HttpsExchange) http;
|
||||||
|
handler.accept(https);
|
||||||
|
// Always respond with 200
|
||||||
|
// * If the reindex sees the 200, it means the SSL connection was established correctly.
|
||||||
|
// * We can check client certs in the handler.
|
||||||
|
https.sendResponseHeaders(200, 0);
|
||||||
|
https.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void shutdownHttpServer() {
|
||||||
|
server.stop(0);
|
||||||
|
server = null;
|
||||||
|
handler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SSLContext buildServerSslContext() throws Exception {
|
||||||
|
final SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
|
||||||
|
final char[] password = "http-password".toCharArray();
|
||||||
|
|
||||||
|
final Path cert = PathUtils.get(ReindexRestClientSslTests.class.getResource("http/http.crt").toURI());
|
||||||
|
final Path key = PathUtils.get(ReindexRestClientSslTests.class.getResource("http/http.key").toURI());
|
||||||
|
final X509ExtendedKeyManager keyManager = new PemKeyConfig(cert, key, password).createKeyManager();
|
||||||
|
|
||||||
|
final Path ca = PathUtils.get(ReindexRestClientSslTests.class.getResource("ca.pem").toURI());
|
||||||
|
final X509ExtendedTrustManager trustManager = new PemTrustConfig(Collections.singletonList(ca)).createTrustManager();
|
||||||
|
|
||||||
|
sslContext.init(new KeyManager[] { keyManager }, new TrustManager[] { trustManager }, null);
|
||||||
|
return sslContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testClientFailsWithUntrustedCertificate() throws IOException {
|
||||||
|
final List<Thread> threads = new ArrayList<>();
|
||||||
|
final Settings settings = Settings.builder()
|
||||||
|
.put("path.home", createTempDir())
|
||||||
|
.build();
|
||||||
|
final Environment environment = TestEnvironment.newEnvironment(settings);
|
||||||
|
final ReindexSslConfig ssl = new ReindexSslConfig(settings, environment, mock(ResourceWatcherService.class));
|
||||||
|
try (RestClient client = TransportReindexAction.buildRestClient(getRemoteInfo(), ssl, 1L, threads)) {
|
||||||
|
expectThrows(SSLHandshakeException.class, () -> client.performRequest(new Request("GET", "/")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testClientSucceedsWithCertificateAuthorities() throws IOException {
|
||||||
|
final List<Thread> threads = new ArrayList<>();
|
||||||
|
final Path ca = getDataPath("ca.pem");
|
||||||
|
final Settings settings = Settings.builder()
|
||||||
|
.put("path.home", createTempDir())
|
||||||
|
.putList("reindex.ssl.certificate_authorities", ca.toString())
|
||||||
|
.build();
|
||||||
|
final Environment environment = TestEnvironment.newEnvironment(settings);
|
||||||
|
final ReindexSslConfig ssl = new ReindexSslConfig(settings, environment, mock(ResourceWatcherService.class));
|
||||||
|
try (RestClient client = TransportReindexAction.buildRestClient(getRemoteInfo(), ssl, 1L, threads)) {
|
||||||
|
final Response response = client.performRequest(new Request("GET", "/"));
|
||||||
|
assertThat(response.getStatusLine().getStatusCode(), Matchers.is(200));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testClientSucceedsWithVerificationDisabled() throws IOException {
|
||||||
|
assertFalse("Cannot disable verification in FIPS JVM", inFipsJvm());
|
||||||
|
final List<Thread> threads = new ArrayList<>();
|
||||||
|
final Settings settings = Settings.builder()
|
||||||
|
.put("path.home", createTempDir())
|
||||||
|
.put("reindex.ssl.verification_mode", "NONE")
|
||||||
|
.build();
|
||||||
|
final Environment environment = TestEnvironment.newEnvironment(settings);
|
||||||
|
final ReindexSslConfig ssl = new ReindexSslConfig(settings, environment, mock(ResourceWatcherService.class));
|
||||||
|
try (RestClient client = TransportReindexAction.buildRestClient(getRemoteInfo(), ssl, 1L, threads)) {
|
||||||
|
final Response response = client.performRequest(new Request("GET", "/"));
|
||||||
|
assertThat(response.getStatusLine().getStatusCode(), Matchers.is(200));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testClientPassesClientCertificate() throws IOException {
|
||||||
|
final List<Thread> threads = new ArrayList<>();
|
||||||
|
final Path ca = getDataPath("ca.pem");
|
||||||
|
final Path cert = getDataPath("client/client.crt");
|
||||||
|
final Path key = getDataPath("client/client.key");
|
||||||
|
final Settings settings = Settings.builder()
|
||||||
|
.put("path.home", createTempDir())
|
||||||
|
.putList("reindex.ssl.certificate_authorities", ca.toString())
|
||||||
|
.put("reindex.ssl.certificate", cert)
|
||||||
|
.put("reindex.ssl.key", key)
|
||||||
|
.put("reindex.ssl.key_passphrase", "client-password")
|
||||||
|
.build();
|
||||||
|
AtomicReference<Certificate[]> clientCertificates = new AtomicReference<>();
|
||||||
|
handler = https -> {
|
||||||
|
try {
|
||||||
|
clientCertificates.set(https.getSSLSession().getPeerCertificates());
|
||||||
|
} catch (SSLPeerUnverifiedException e) {
|
||||||
|
logger.warn("Client did not provide certificates", e);
|
||||||
|
clientCertificates.set(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
final Environment environment = TestEnvironment.newEnvironment(settings);
|
||||||
|
final ReindexSslConfig ssl = new ReindexSslConfig(settings, environment, mock(ResourceWatcherService.class));
|
||||||
|
try (RestClient client = TransportReindexAction.buildRestClient(getRemoteInfo(), ssl, 1L, threads)) {
|
||||||
|
final Response response = client.performRequest(new Request("GET", "/"));
|
||||||
|
assertThat(response.getStatusLine().getStatusCode(), Matchers.is(200));
|
||||||
|
final Certificate[] certs = clientCertificates.get();
|
||||||
|
assertThat(certs, Matchers.notNullValue());
|
||||||
|
assertThat(certs, Matchers.arrayWithSize(1));
|
||||||
|
assertThat(certs[0], Matchers.instanceOf(X509Certificate.class));
|
||||||
|
final X509Certificate clientCert = (X509Certificate) certs[0];
|
||||||
|
assertThat(clientCert.getSubjectDN().getName(), Matchers.is("CN=client"));
|
||||||
|
assertThat(clientCert.getIssuerDN().getName(), Matchers.is("CN=Elastic Certificate Tool Autogenerated CA"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private RemoteInfo getRemoteInfo() {
|
||||||
|
return new RemoteInfo("https", server.getAddress().getHostName(), server.getAddress().getPort(), "/", new BytesArray("test"),
|
||||||
|
"user", "password", Collections.emptyMap(), RemoteInfo.DEFAULT_SOCKET_TIMEOUT, RemoteInfo.DEFAULT_CONNECT_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressForbidden(reason = "use http server")
|
||||||
|
private static class ClientAuthHttpsConfigurator extends HttpsConfigurator {
|
||||||
|
ClientAuthHttpsConfigurator(SSLContext sslContext) {
|
||||||
|
super(sslContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(HttpsParameters params) {
|
||||||
|
params.setWantClientAuth(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,9 +20,14 @@
|
||||||
package org.elasticsearch.index.reindex;
|
package org.elasticsearch.index.reindex;
|
||||||
|
|
||||||
import org.elasticsearch.action.index.IndexRequest;
|
import org.elasticsearch.action.index.IndexRequest;
|
||||||
|
import org.elasticsearch.action.support.ActionFilters;
|
||||||
import org.elasticsearch.common.lucene.uid.Versions;
|
import org.elasticsearch.common.lucene.uid.Versions;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.script.ScriptService;
|
import org.elasticsearch.script.ScriptService;
|
||||||
|
import org.elasticsearch.transport.TransportService;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
@ -103,7 +108,11 @@ public class ReindexScriptTests extends AbstractAsyncBulkByScrollActionScriptTes
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TransportReindexAction.AsyncIndexBySearchAction action(ScriptService scriptService, ReindexRequest request) {
|
protected TransportReindexAction.AsyncIndexBySearchAction action(ScriptService scriptService, ReindexRequest request) {
|
||||||
return new TransportReindexAction.AsyncIndexBySearchAction(task, logger, null, threadPool, request, scriptService,
|
TransportService transportService = Mockito.mock(TransportService.class);
|
||||||
null, listener());
|
ReindexSslConfig sslConfig = Mockito.mock(ReindexSslConfig.class);
|
||||||
|
TransportReindexAction transportAction = new TransportReindexAction(Settings.EMPTY, threadPool,
|
||||||
|
new ActionFilters(Collections.emptySet()), null, null, scriptService, null, null, transportService, sslConfig);
|
||||||
|
return new TransportReindexAction.AsyncIndexBySearchAction(task, logger, null, threadPool, transportAction, request,
|
||||||
|
null, listener());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ public class UpdateByQueryMetadataTests
|
||||||
private class TestAction extends TransportUpdateByQueryAction.AsyncIndexBySearchAction {
|
private class TestAction extends TransportUpdateByQueryAction.AsyncIndexBySearchAction {
|
||||||
TestAction() {
|
TestAction() {
|
||||||
super(UpdateByQueryMetadataTests.this.task, UpdateByQueryMetadataTests.this.logger, null,
|
super(UpdateByQueryMetadataTests.this.task, UpdateByQueryMetadataTests.this.logger, null,
|
||||||
UpdateByQueryMetadataTests.this.threadPool, request(), null, ClusterState.EMPTY_STATE, listener());
|
UpdateByQueryMetadataTests.this.threadPool, null, request(), ClusterState.EMPTY_STATE, listener());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -19,13 +19,17 @@
|
||||||
|
|
||||||
package org.elasticsearch.index.reindex;
|
package org.elasticsearch.index.reindex;
|
||||||
|
|
||||||
|
import org.elasticsearch.action.support.ActionFilters;
|
||||||
import org.elasticsearch.cluster.ClusterState;
|
import org.elasticsearch.cluster.ClusterState;
|
||||||
import org.elasticsearch.script.ScriptService;
|
import org.elasticsearch.script.ScriptService;
|
||||||
|
import org.elasticsearch.transport.TransportService;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
public class UpdateByQueryWithScriptTests
|
public class UpdateByQueryWithScriptTests
|
||||||
extends AbstractAsyncBulkByScrollActionScriptTestCase<UpdateByQueryRequest, BulkByScrollResponse> {
|
extends AbstractAsyncBulkByScrollActionScriptTestCase<UpdateByQueryRequest, BulkByScrollResponse> {
|
||||||
|
@ -54,7 +58,10 @@ public class UpdateByQueryWithScriptTests
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TransportUpdateByQueryAction.AsyncIndexBySearchAction action(ScriptService scriptService, UpdateByQueryRequest request) {
|
protected TransportUpdateByQueryAction.AsyncIndexBySearchAction action(ScriptService scriptService, UpdateByQueryRequest request) {
|
||||||
return new TransportUpdateByQueryAction.AsyncIndexBySearchAction(task, logger, null, threadPool, request, scriptService,
|
TransportService transportService = mock(TransportService.class);
|
||||||
|
TransportUpdateByQueryAction transportAction = new TransportUpdateByQueryAction(threadPool,
|
||||||
|
new ActionFilters(Collections.emptySet()), null, transportService, scriptService, null);
|
||||||
|
return new TransportUpdateByQueryAction.AsyncIndexBySearchAction(task, logger, null, threadPool, transportAction, request,
|
||||||
ClusterState.EMPTY_STATE, listener());
|
ClusterState.EMPTY_STATE, listener());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
# ca.p12
|
||||||
|
|
||||||
|
$ES_HOME/bin/elasticsearch-certutil ca --out ca.p12 --pass "ca-password" --days 9999
|
||||||
|
|
||||||
|
# ca.pem
|
||||||
|
|
||||||
|
openssl pkcs12 -info -in ./ca.p12 -nokeys -out ca.pem -passin "pass:ca-password"
|
||||||
|
|
||||||
|
# http.p12
|
||||||
|
|
||||||
|
$ES_HOME/bin/elasticsearch-certutil cert --out http.zip --pass "http-password" \
|
||||||
|
--days 9999 --pem --name "http" \
|
||||||
|
--ca ca.p12 --ca-pass "ca-password" \
|
||||||
|
--dns=localhost --dns=localhost.localdomain --dns=localhost4 --dns=localhost4.localdomain4 --dns=localhost6 --dns=localhost6.localdomain6 \
|
||||||
|
--ip=127.0.0.1 --ip=0:0:0:0:0:0:0:1
|
||||||
|
unzip http.zip
|
||||||
|
rm http.zip
|
||||||
|
|
||||||
|
# client.p12
|
||||||
|
|
||||||
|
$ES_HOME/bin/elasticsearch-certutil cert --out client.zip --pass "client-password" \
|
||||||
|
--name "client" --days 9999 --pem \
|
||||||
|
--ca ca.p12 --ca-pass "ca-password"
|
||||||
|
unzip client.zip
|
||||||
|
rm client.zip
|
Binary file not shown.
|
@ -0,0 +1,25 @@
|
||||||
|
Bag Attributes
|
||||||
|
friendlyName: ca
|
||||||
|
localKeyID: 54 69 6D 65 20 31 35 34 37 30 38 36 32 32 39 31 30 37
|
||||||
|
subject=/CN=Elastic Certificate Tool Autogenerated CA
|
||||||
|
issuer=/CN=Elastic Certificate Tool Autogenerated CA
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDSTCCAjGgAwIBAgIUacmv5ElKJ1cs9n61tEpy5KM3Dv0wDQYJKoZIhvcNAQEL
|
||||||
|
BQAwNDEyMDAGA1UEAxMpRWxhc3RpYyBDZXJ0aWZpY2F0ZSBUb29sIEF1dG9nZW5l
|
||||||
|
cmF0ZWQgQ0EwHhcNMTkwMTEwMDIxMDI5WhcNNDYwNTI3MDIxMDI5WjA0MTIwMAYD
|
||||||
|
VQQDEylFbGFzdGljIENlcnRpZmljYXRlIFRvb2wgQXV0b2dlbmVyYXRlZCBDQTCC
|
||||||
|
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ0rA35tPl0FN+BPk2YfmET9
|
||||||
|
MvDWFLvfL2Z1aw1q1vnd12K9zumjN6veilHA2Iw/P4LG/mkQZvY4bDPgibRD7hbE
|
||||||
|
vwPoju4vr614tw60+FlkpO6HezYo2I3cni1//Gehhs5EW2P3g7Lw7UNCOAfcR2QQ
|
||||||
|
p/dtwXYWzXHY9jTevQSv2q/x5jWKZT4ltaQExzvXAcxRGqyWV6d5vol3KH/GpCSI
|
||||||
|
SQvRmRVNQGXhxi66MjCglGAM2oicd1qCUDCrljdFD/RQ1UzqIJRTXZQKOno1/Em9
|
||||||
|
xR0Cd5KQapqttPusAO6uZblMO2Ru+XjCD6Y0o41eCDbkd0xA3/wgP3MD5n41yncC
|
||||||
|
AwEAAaNTMFEwHQYDVR0OBBYEFJTry9da5RZbbELYCaWVVFllSm8DMB8GA1UdIwQY
|
||||||
|
MBaAFJTry9da5RZbbELYCaWVVFllSm8DMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
|
||||||
|
hvcNAQELBQADggEBADA6qhC35PwuL7LRddbhjjW8U/cCmG9m7AIvH6N+Mw/k76gt
|
||||||
|
tJkEDxztMHUG+A2IPyEcYm7MLr1D8xEQYsq0x4pzFcQnMSQDv4WTK35vRxMtaqwA
|
||||||
|
WZTyA+DibBknbaP1z3gNhR9A0TKx4cPagN3OYFvAi/24abf8qS6D/bcOiPDQ4oPb
|
||||||
|
DVhmhqt5zduDM+Xsf6d4nsA6sf9+4AzneaZKGAMgCXgo4mYeP7M4nMQk0L3ao9Ts
|
||||||
|
+Usr8WRxc4xHGyb09fsXWSz7ZmiJ6iXK2NvRUq46WCINLONLzNkx29WEKQpI3wh4
|
||||||
|
kyx6wF9lwBF06P1raFIBMeMOCkqDc+nj7A91PEA=
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -0,0 +1,19 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDIDCCAgigAwIBAgIUNOREYZadZ2EVkJ1m8Y9jnVmWmtAwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwNDEyMDAGA1UEAxMpRWxhc3RpYyBDZXJ0aWZpY2F0ZSBUb29sIEF1dG9nZW5l
|
||||||
|
cmF0ZWQgQ0EwHhcNMTkwMTEwMDIxMDMyWhcNNDYwNTI3MDIxMDMyWjARMQ8wDQYD
|
||||||
|
VQQDEwZjbGllbnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCCP2LE
|
||||||
|
nws2+ZIwSQ3IvIhVfrueUmNt7Y5TdhhwO32p2wC4ZA62J9L8klAzt7R+izcL/qbF
|
||||||
|
65inbXM0A7ge/2wZ09kbqBk5uS8jDetJS8lQmWVZDHfVi8g/yDMWklz2mQYleYmU
|
||||||
|
HPyIplai3P3KBoT8HurzHw2C953EZ2HiANFnGoEPZZ5ytcT2WenxuU5kSXSxuDyn
|
||||||
|
8/dCVHEQL1Yipr2LQKYQAHotjo56OhyL9KS5YPjzSFREeyRfQinssTmpGFsua/PK
|
||||||
|
Vqj+hRdkaqRfiqPq3wxn8oOSpZLQe58O1e7OlqgjkPuZdjZ0pQ7KJj7N3fUQNSeg
|
||||||
|
2VC2tk8zv/C/Qr2bAgMBAAGjTTBLMB0GA1UdDgQWBBQziDNuD83ZLwEt1e1txYJu
|
||||||
|
oSseEDAfBgNVHSMEGDAWgBSU68vXWuUWW2xC2AmllVRZZUpvAzAJBgNVHRMEAjAA
|
||||||
|
MA0GCSqGSIb3DQEBCwUAA4IBAQAPpyWyR4w6GvfvPmA1nk1qd7fsQ1AucrYweIJx
|
||||||
|
dTeXg3Ps1bcgNq9Us9xtsKmsoKD8UhtPN6e8W8MkMmri+MSzlEemE+pJZrjHEudi
|
||||||
|
Sj0AFVOK6jaE0lerbCnTQZvYH+J9Eb1i9RP7XHRShkR4MWgy2BzlENk9/LRbr84W
|
||||||
|
Yf5TuM9+ApiiiOoX9UfSGBzNnqwhJNpG9yJ+HnQSqTnJJc/wL0211zLme9I/nhf0
|
||||||
|
kQx6mPedJ3gGoJ8gqz38djIrhJDxq+0Bd9SsdlR6yT+1+bY7hinYx2eLV91AybZ4
|
||||||
|
x07Kyl174DD41PYaE1AtoLlrMrQ5BG7Md50Am+XXOR1X1dkZ
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -0,0 +1,30 @@
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
Proc-Type: 4,ENCRYPTED
|
||||||
|
DEK-Info: DES-EDE3-CBC,81AB10154C04B38F
|
||||||
|
|
||||||
|
0L6Buvpeg6QHh/mbYp/3bXDCsu0k0j5xPdIGWd6NCOdb24OQFsOjeA2WuPqs0WWF
|
||||||
|
gzVrjh984biS3IqeglEr6X6PfVJ0QOgBkq0XgSBXhuoRJL/302N9oPGsf8T8oW9t
|
||||||
|
pqR/JIB2L7lMbJlJYSjMl0YQT3hWpo2BlrtSIc/GWOKfjDNWc9BL+oHvKJwql1lb
|
||||||
|
n4yMvYFYJDqgzgxa3r4IIQNsCn3SP+gqbTx9vF6StOIroV51BdSL4IGWRvqnMJrh
|
||||||
|
ybk1EHSLR1oGcONLU4Ksi33UxdImG70SsnoH/NnInDvV2bxmxmgf5SfYKtxFhoxz
|
||||||
|
0hISKTMTerPGtRQ5p8wtEi/ULKyInK+qF3tLgZa+S5VbByjDnUo2dCcbDDSkH5pO
|
||||||
|
uczJ2bs1kJegpCrUueJdbi9OX2upmF+tJb9+5hzFTvey8dUWTEpdiN0xbp4BLfNd
|
||||||
|
Yp4sMHZovsDJKIjDb0NbXRgLeFh1ijlLPhKwIXWTF3BaCKcSw34Qv22YPwn3qNuw
|
||||||
|
0KuUPAo0B65R/hoJguvtks8QAXe0S1jZS/fAlQCoIB0TIduy1qkyje+AnSW+1RL0
|
||||||
|
ysBxLqbvRUqWlgnu7/28V4FD8JNu3O+UGBEelXlfokLgCBZ6lSys2d3Zy/XVBnG0
|
||||||
|
cPl59if+fxKaMWlhFvMLFBup1Y4a/1zA7Sx6kkhvawekHr40NcG4kLHJ+O6UoM4d
|
||||||
|
/ibnbfIksLNkuo/nwoEcKp7W6SxafV0hROdxClkGKild66rnHtk4IGATjaBqt9nr
|
||||||
|
FuO3vRtLuUMS+/4kpvhMwl0RhX2/i6xgV+klWNYNu1JTGDFvdG3qfiY2w88EIbGe
|
||||||
|
rn8JEvRtaH/XNeGdhBwbuObvTifiHyYzA1i5Zh8zvE2+Dthlk19jbBoOUx//LOi2
|
||||||
|
JrNkAsqQCF4HXh7n9HWA/ZrKTP7Xvkig6Vf7M2Y/tO361LSJfzKcRFLpl0P2ntEv
|
||||||
|
XwFOqTvOURERTVr4sBLOVPRAhIs3yvkI5xfurXzbRWtSeLgrMoDgJlXIQbuXd8sq
|
||||||
|
zIBLqvYf2bcroB66XJqX1IFWEstym/NHGcbrwjR5Fn2p3YAtXnIbw8VhHwV+LIOl
|
||||||
|
ky/wH9vbnML/DE81qFqRe8vNZw2sGn9skOyU/QvKeV1NRHYZSV3hMx82bPnjgFeB
|
||||||
|
ilzkb8FEPOAOJ0m44Q3C9eUoazJT8aCuRIAgSL43se1E2pFlIXQTfYRARaWEkSf9
|
||||||
|
0hXqQJc17b+Hj0ire3PUqbG3+/l1qMhhIHwq7Kuyy2neTuW/DXbXp2AMv/bLcnHH
|
||||||
|
apVeRZaYXVSnGXJNk2CeRnCs8OGir8g5zkH+fmVb9knt6TL2oFIsQqULyrLolhfe
|
||||||
|
6Q8mLzq/sd+w+VuN1n/5+RQqOJZWEkLFzQPx8wTqeTB19OE0gjncrqzCHq7INqRe
|
||||||
|
tGClWOj/yL0Sciu3ctVGz1VAbgeBKnLdKm2TX4oFB4OG4E7GMXIL7hGxjtjLAVMW
|
||||||
|
XNc3ZYNQra+iPqJtFxnmbrF2Sn0Wr0hcAT1V0A0TRKe/n0lpUrfhTy/q4DUlOVKG
|
||||||
|
qdCsTGoYXObpUWU5G9GyCVWWRJyrTxJcBZ9KWJu9Y/aMFzoa2n0HQw==
|
||||||
|
-----END RSA PRIVATE KEY-----
|
|
@ -0,0 +1,22 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDsjCCApqgAwIBAgIUXxlg/0/g3UYekXWBRpkHM84EYfIwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwNDEyMDAGA1UEAxMpRWxhc3RpYyBDZXJ0aWZpY2F0ZSBUb29sIEF1dG9nZW5l
|
||||||
|
cmF0ZWQgQ0EwHhcNMTkwMTEwMDIxMDMwWhcNNDYwNTI3MDIxMDMwWjAPMQ0wCwYD
|
||||||
|
VQQDEwRodHRwMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi8VQaSR6
|
||||||
|
uqgT1Rkw+a39OSXcXuhJBVdoO+AyYPK7hdUTxj1aqnXkKeAiNGpe/J+uXZ837Spy
|
||||||
|
rmBZS3k6S5hLEceF2xug8yrR7RYEZ+JvGlRgg/jj+61gGbHAD314+vvu0YUo06YG
|
||||||
|
wbz9AnjJA/sMbsCp3iSzWIkwZBZcCoZ/YsG4I89LSjYL3YmRi2193WMX6/OfQYMN
|
||||||
|
Fkv61r/iwBEkgJ14cUSYe3norGuQfZuXSh5kI5D5R7q7Bmb0um+jzY/l62kj3oR1
|
||||||
|
YWo3g6DdU/Bc/3/KmEEVXIfdTonMBMyL8PvYORoMKrYdph3E8e39ZQhPeBJNJKw0
|
||||||
|
XzsZFzIUlTw0kQIDAQABo4HgMIHdMB0GA1UdDgQWBBTiqknjZLa5E1BneHRvTkNa
|
||||||
|
Bm4nNTAfBgNVHSMEGDAWgBSU68vXWuUWW2xC2AmllVRZZUpvAzCBjwYDVR0RBIGH
|
||||||
|
MIGEgglsb2NhbGhvc3SCF2xvY2FsaG9zdDYubG9jYWxkb21haW42hwR/AAABhxAA
|
||||||
|
AAAAAAAAAAAAAAAAAAABggpsb2NhbGhvc3Q0ggpsb2NhbGhvc3Q2ghVsb2NhbGhv
|
||||||
|
c3QubG9jYWxkb21haW6CF2xvY2FsaG9zdDQubG9jYWxkb21haW40MAkGA1UdEwQC
|
||||||
|
MAAwDQYJKoZIhvcNAQELBQADggEBAIZr8EhhCbNyc6iHzUJ/NrUGht5RDHUKN9WU
|
||||||
|
2fd+SJlWijQYGoFW6LfabmYxIVPAFtYzUiA378NFoOZZ4kdC3gQng8izvS2UDcO6
|
||||||
|
cAG5q/dxop3VXqcLeK3NpH2jd83M8VZaOThPj/F07eTkVX+sGu+7VL5Lc/XPe8JS
|
||||||
|
HhH2QtcTPGPpzPnWOUMLpRy4mh5sDyeftWr2PTFgMXFD6dtzDvaklGJvr1TmcOVb
|
||||||
|
BFYyVyXRq6v8YsrRPp0GIl+X3zd3KgwUMuEzRKkJgeI1lZRjmHMIyFcqxlwMaHpv
|
||||||
|
r1XUmz02ycy6t3n+2kCgfU6HnjbeFh55KzNCEv8TXQFg8Z8YpDA=
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -0,0 +1,30 @@
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
Proc-Type: 4,ENCRYPTED
|
||||||
|
DEK-Info: DES-EDE3-CBC,127A4142FA81C5A1
|
||||||
|
|
||||||
|
dP6oSAUl47KCnP0YZSX108qcX5s2nVGpD0qtnVQg89mLVFd7IxpKQaIuODSadRTo
|
||||||
|
AD0KINITy3ZwUr/TTJgERu88baBsTHv3PLEe7TpQI2DGGDz3aZfO9e6Jvglbdi5b
|
||||||
|
CBLaxRXGGhhH9YH0E87Lp3JEwg4udWmlNahGIhbqNheZNTtDKt+Lx80TyyIml2r/
|
||||||
|
GAhjT4UPvIRrATFAcL/3EKOjRqvb6SeGnZu21n2TSmsBEr02gC0Ox3qmsnRM3kvU
|
||||||
|
jCuUzWTzJSQLXZwZuMtv5srOSFAbU8EklFXNhWJU/7GBy215aAAW48hCzkPMVEbg
|
||||||
|
oeH4nuze/Uulih9UxJGCBIpvfTnksyMRGP/zdy1mnKuqQk+yI0n7JWMJL8QoDQc8
|
||||||
|
XvzqOmKLdBVezmzOVP/PyMAhYWetILh/1UesjyJot2hwSXPAxqBHPVA9bnmel6CQ
|
||||||
|
VccNSwaK120yT5YhkUMFc0AmUpztzNMQzJ10g1dW+Qsr+n4vtFmAuTvBgogNNVXn
|
||||||
|
eX1hbbiXGO1Fw4OMu6qTJ4T/P+VFb0CxoxETWeqdjcs4LGbeqF68nayEsW0ZzhbI
|
||||||
|
W5c+JAbW18Kb+k/KzKZTtJEXBw6B/2FMe9x9z3BIpVhplM2KsNk7joWnumD8LfUT
|
||||||
|
ORRHUPV7bkdiDsn2CRaevubDQiChcjsdLWhG7JLm54ttyif7/X7htGOXPZLDLK8B
|
||||||
|
Vxe09B006f7lM0tXEx8BLFDNroMLlrxB4K5MlwWpS3LLqy4zDbHka2I3s/ST/BD4
|
||||||
|
0EURHefiXJkR6bRsfGCl3JDk0EakcUXM+Ob5/2rC/rPXO2pC0ksiQ2DSBm7ak9om
|
||||||
|
vlC7dIzVipL0LZTd4SUDJyvmK4Ws6V98O5b+79To6oZnVs5CjvcmpSFVePZa5gm/
|
||||||
|
DB8LOpW4jklz+ybJtHJRbEIzmpfwpizThto/zLbhPRyvJkagJfWgXI0j+jjKZj+w
|
||||||
|
sy1V8S44aXJ3GX9p4d/Grnx6WGvEJSV0na7m3YQCPEi5sUgr+EMizGUYstSSUPtU
|
||||||
|
XhxQRZ95K2cKORul9vzG3zZqqvi73Ju5vu9DLmmlI00sLzyVGFtvkuhrF2p7XclM
|
||||||
|
GU/rMOeMClMb6qyCzldSs84Anhlh/6mYri6uYPhIGvxqtH44FTbu1APvZp0s2rVm
|
||||||
|
ueClHG78lat+oqWFpbA8+peT0dMPdSKDAFDiHsGoeWCIoCF44a84bJX35OZk+Y4a
|
||||||
|
+fDFuSiKYBMfAgqf/ZNzV4+ySka7dWdRQ2TDgIuxnvFV1NgC/ir3/mPgkf0xZU5d
|
||||||
|
w8T+TW6T8PmJfHnW4nxgHaqgxMoEoPm8zn0HNpRFKwsDYRFfobpCXnoyx50JXxa4
|
||||||
|
jg095zlp8X0JwconlGJB1gfeqvS2I50WEDR+2ZtDf7fUEnQ3LYJzP4lSwiSKiQsQ
|
||||||
|
MPjy0SMQnqmWijylLYKunTl3Uh2DdYg4MOON662H3TxQW8TCYwK2maKujwS9VFLN
|
||||||
|
GtRGlLrOtrOfHBSwDCujFjqEmQBsF/y2C6XfMoNq6xi5NzREGmNXYrHbLvl2Njwm
|
||||||
|
WB1ouB4JzmEmb1QNwxkllBAaUp1SJGhW2+fYOe0zjWOP9R4sUq4rRw==
|
||||||
|
-----END RSA PRIVATE KEY-----
|
Loading…
Reference in New Issue