mirror of https://github.com/apache/druid.git
Mutual TLS support (#6076)
* Mutual TLS support * Kafka test fixes * TeamCity fix * Split integration tests * Use localhost DOCKER_IP * Increase server thread count * Increase SSL handshake timeouts * Add broken pipe retries, use injected client config params * PR comments, Rat license check exclusion
This commit is contained in:
parent
4fafc2ccc9
commit
8972244c68
25
.travis.yml
25
.travis.yml
|
@ -93,8 +93,8 @@ matrix:
|
|||
services:
|
||||
- docker
|
||||
env:
|
||||
- NAME="integration test"
|
||||
- DOCKER_IP=172.17.0.1
|
||||
- NAME="integration test part 1"
|
||||
- DOCKER_IP=127.0.0.1
|
||||
install:
|
||||
# Only errors will be shown with the -q option. This is to avoid generating too many logs which make travis build failed.
|
||||
- mvn install -q -ff -DskipTests -B
|
||||
|
@ -108,3 +108,24 @@ matrix:
|
|||
echo $v dmesg ======================== ;
|
||||
docker exec -it druid-$v sh -c 'dmesg | tail -3' ;
|
||||
done
|
||||
|
||||
# run integration tests
|
||||
- sudo: required
|
||||
services:
|
||||
- docker
|
||||
env:
|
||||
- NAME="integration test part 2"
|
||||
- DOCKER_IP=127.0.0.1
|
||||
install:
|
||||
# Only errors will be shown with the -q option. This is to avoid generating too many logs which make travis build failed.
|
||||
- mvn install -q -ff -DskipTests -B
|
||||
script:
|
||||
- $TRAVIS_BUILD_DIR/ci/travis_script_integration_part2.sh
|
||||
after_failure:
|
||||
- for v in ~/shared/logs/*.log ; do
|
||||
echo $v logtail ======================== ; tail -100 $v ;
|
||||
done
|
||||
- for v in broker middlemanager overlord router coordinator historical ; do
|
||||
echo $v dmesg ======================== ;
|
||||
docker exec -it druid-$v sh -c 'dmesg | tail -3' ;
|
||||
done
|
||||
|
|
|
@ -21,6 +21,6 @@ set -e
|
|||
|
||||
pushd $TRAVIS_BUILD_DIR/integration-tests
|
||||
|
||||
mvn verify -P integration-tests
|
||||
mvn verify -P integration-tests -Dit.test=ITAppenderatorDriverRealtimeIndexTaskTest,ITCompactionTaskTest,ITIndexerTest,ITKafkaIndexingServiceTest,ITKafkaTest,ITParallelIndexTest,ITRealtimeIndexTaskTest
|
||||
|
||||
popd
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF 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.
|
||||
|
||||
set -e
|
||||
|
||||
pushd $TRAVIS_BUILD_DIR/integration-tests
|
||||
|
||||
mvn verify -P integration-tests -Dit.test=ITUnionQueryTest,ITTwitterQueryTest,ITWikipediaQueryTest,ITBasicAuthConfigurationTest,ITTLSTest
|
||||
|
||||
popd
|
|
@ -18,5 +18,16 @@ Java's SSL support, please refer to [this](http://docs.oracle.com/javase/8/docs/
|
|||
|`druid.client.https.trustStoreAlgorithm`|Algorithm to be used by TrustManager to validate certificate chains|`javax.net.ssl.TrustManagerFactory.getDefaultAlgorithm()`|no|
|
||||
|`druid.client.https.trustStorePassword`|The [Password Provider](../../operations/password-provider.html) or String password for the Trust Store.|none|yes|
|
||||
|
||||
The following table contains optional parameters for supporting client certificate authentication:
|
||||
|
||||
|Property|Description|Default|Required|
|
||||
|--------|-----------|-------|--------|
|
||||
|`druid.client.https.keyStorePath`|The file path or URL of the TLS/SSL Key store containing the client certificate that Druid will use when communicating with other Druid services. If this is null, the other properties in this table are ignored.|none|yes|
|
||||
|`druid.client.https.keyStoreType`|The type of the key store.|none|yes|
|
||||
|`druid.client.https.certAlias`|Alias of TLS client certificate in the keystore.|none|yes|
|
||||
|`druid.client.https.keyStorePassword`|The [Password Provider](../operations/password-provider.html) or String password for the Key Store.|none|no|
|
||||
|`druid.client.https.keyManagerFactoryAlgorithm`|Algorithm to use for creating KeyManager, more details [here](https://docs.oracle.com/javase/7/docs/technotes/guides/security/jsse/JSSERefGuide.html#KeyManager).|`javax.net.ssl.KeyManagerFactory.getDefaultAlgorithm()`|no|
|
||||
|`druid.client.https.keyManagerPassword`|The [Password Provider](../operations/password-provider.html) or String password for the Key Manager.|none|no|
|
||||
|
||||
This [document](http://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html) lists all the possible
|
||||
values for the above mentioned configs among others provided by Java implementation.
|
|
@ -31,7 +31,19 @@ values for the below mentioned configs among others provided by Java implementat
|
|||
|`druid.server.https.certAlias`|Alias of TLS/SSL certificate for the connector.|none|yes|
|
||||
|`druid.server.https.keyStorePassword`|The [Password Provider](../operations/password-provider.html) or String password for the Key Store.|none|yes|
|
||||
|
||||
Following table contains non-mandatory advanced configuration options, use caution.
|
||||
The following table contains configuration options related to client certificate authentication.
|
||||
|
||||
|Property|Description|Default|Required|
|
||||
|--------|-----------|-------|--------|
|
||||
|`druid.server.https.requireClientCertificate`|If set to true, clients must identify themselves by providing a TLS certificate. If `requireClientCertificate` is false, the rest of the options in this table are ignored.|false|no|
|
||||
|`druid.server.https.trustStoreType`|The type of the trust store containing certificates used to validate client certificates. Not needed if `requireClientCertificate` is false.|`java.security.KeyStore.getDefaultType()`|no|
|
||||
|`druid.server.https.trustStorePath`|The file path or URL of the trust store containing certificates used to validate client certificates. Not needed if `requireClientCertificate` is false.|none|yes, only if `requireClientCertificate` is true|
|
||||
|`druid.server.https.trustStoreAlgorithm`|Algorithm to be used by TrustManager to validate client certificate chains. Not needed if `requireClientCertificate` is false.|`javax.net.ssl.TrustManagerFactory.getDefaultAlgorithm()`|no|
|
||||
|`druid.server.https.trustStorePassword`|The [Password Provider](../../operations/password-provider.html) or String password for the Trust Store. Not needed if `requireClientCertificate` is false.|none|no|
|
||||
|`druid.server.https.validateHostnames`|If set to true, check that the client's hostname matches the CN/subjectAltNames in the client certificate. Not used if `requireClientCertificate` is false.|true|no|
|
||||
|`druid.server.https.crlPath`|Specifies a path to a file containing static [Certificate Revocation Lists](https://en.wikipedia.org/wiki/Certificate_revocation_list), used to check if a client certificate has been revoked. Not used if `requireClientCertificate` is false.|null|no|
|
||||
|
||||
The following table contains non-mandatory advanced configuration options, use caution.
|
||||
|
||||
|Property|Description|Default|Required|
|
||||
|--------|-----------|-------|--------|
|
||||
|
|
|
@ -39,6 +39,24 @@ public class SSLClientConfig
|
|||
@JsonProperty("trustStorePassword")
|
||||
private PasswordProvider trustStorePasswordProvider;
|
||||
|
||||
@JsonProperty
|
||||
private String keyStorePath;
|
||||
|
||||
@JsonProperty
|
||||
private String keyStoreType;
|
||||
|
||||
@JsonProperty
|
||||
private String certAlias;
|
||||
|
||||
@JsonProperty("keyStorePassword")
|
||||
private PasswordProvider keyStorePasswordProvider;
|
||||
|
||||
@JsonProperty("keyManagerPassword")
|
||||
private PasswordProvider keyManagerPasswordProvider;
|
||||
|
||||
@JsonProperty
|
||||
private String keyManagerFactoryAlgorithm;
|
||||
|
||||
public String getProtocol()
|
||||
{
|
||||
return protocol;
|
||||
|
@ -64,6 +82,36 @@ public class SSLClientConfig
|
|||
return trustStorePasswordProvider;
|
||||
}
|
||||
|
||||
public String getKeyStorePath()
|
||||
{
|
||||
return keyStorePath;
|
||||
}
|
||||
|
||||
public String getKeyStoreType()
|
||||
{
|
||||
return keyStoreType;
|
||||
}
|
||||
|
||||
public PasswordProvider getKeyStorePasswordProvider()
|
||||
{
|
||||
return keyStorePasswordProvider;
|
||||
}
|
||||
|
||||
public String getCertAlias()
|
||||
{
|
||||
return certAlias;
|
||||
}
|
||||
|
||||
public PasswordProvider getKeyManagerPasswordProvider()
|
||||
{
|
||||
return keyManagerPasswordProvider;
|
||||
}
|
||||
|
||||
public String getKeyManagerFactoryAlgorithm()
|
||||
{
|
||||
return keyManagerFactoryAlgorithm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
@ -72,6 +120,10 @@ public class SSLClientConfig
|
|||
", trustStoreType='" + trustStoreType + '\'' +
|
||||
", trustStorePath='" + trustStorePath + '\'' +
|
||||
", trustStoreAlgorithm='" + trustStoreAlgorithm + '\'' +
|
||||
", keyStorePath='" + keyStorePath + '\'' +
|
||||
", keyStoreType='" + keyStoreType + '\'' +
|
||||
", certAlias='" + certAlias + '\'' +
|
||||
", keyManagerFactoryAlgorithm='" + keyManagerFactoryAlgorithm + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,12 +43,18 @@ public class SSLContextProvider implements Provider<SSLContext>
|
|||
{
|
||||
log.info("Creating SslContext for https client using config [%s]", config);
|
||||
|
||||
return TLSUtils.createSSLContext(
|
||||
config.getProtocol(),
|
||||
config.getTrustStoreType(),
|
||||
config.getTrustStorePath(),
|
||||
config.getTrustStoreAlgorithm(),
|
||||
config.getTrustStorePasswordProvider()
|
||||
);
|
||||
return new TLSUtils.ClientSSLContextBuilder()
|
||||
.setProtocol(config.getProtocol())
|
||||
.setTrustStoreType(config.getTrustStoreType())
|
||||
.setTrustStorePath(config.getTrustStorePath())
|
||||
.setTrustStoreAlgorithm(config.getTrustStoreAlgorithm())
|
||||
.setTrustStorePasswordProvider(config.getTrustStorePasswordProvider())
|
||||
.setKeyStoreType(config.getKeyStoreType())
|
||||
.setKeyStorePath(config.getKeyStorePath())
|
||||
.setKeyStoreAlgorithm(config.getKeyManagerFactoryAlgorithm())
|
||||
.setCertAlias(config.getCertAlias())
|
||||
.setKeyStorePasswordProvider(config.getKeyStorePasswordProvider())
|
||||
.setKeyManagerFactoryPasswordProvider(config.getKeyManagerPasswordProvider())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
client_tls/
|
||||
docker/docker_ip
|
||||
docker/tls/root.key
|
||||
docker/tls/root.pem
|
||||
docker/tls/untrusted_root.key
|
||||
docker/tls/untrusted_root.pem
|
|
@ -39,32 +39,43 @@ RUN find /var/lib/mysql -type f -exec touch {} \; && service mysql start \
|
|||
# Setup supervisord
|
||||
ADD supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
|
||||
# mysql
|
||||
ADD run-mysql.sh /run-mysql.sh
|
||||
|
||||
# internal docker_ip:9092 endpoint is used to access Kafka from other Docker containers
|
||||
# external docker ip:9093 endpoint is used to access Kafka from test code
|
||||
# run this last to avoid rebuilding the image every time the ip changes
|
||||
ADD docker_ip docker_ip
|
||||
RUN perl -pi -e "s/#listeners=.*/listeners=INTERNAL:\/\/$(resolveip -s $HOSTNAME):9092,EXTERNAL:\/\/$(resolveip -s $HOSTNAME):9093/" /usr/local/kafka/config/server.properties
|
||||
RUN perl -pi -e "s/#advertised.listeners=.*/advertised.listeners=INTERNAL:\/\/$(resolveip -s $HOSTNAME):9092,EXTERNAL:\/\/$(cat docker_ip):9093/" /usr/local/kafka/config/server.properties
|
||||
RUN perl -pi -e "s/#listeners=.*/listeners=INTERNAL:\/\/172.172.172.2:9092,EXTERNAL:\/\/172.172.172.2:9093/" /usr/local/kafka/config/server.properties
|
||||
RUN perl -pi -e "s/#advertised.listeners=.*/advertised.listeners=INTERNAL:\/\/172.172.172.2:9092,EXTERNAL:\/\/$(cat docker_ip):9093/" /usr/local/kafka/config/server.properties
|
||||
RUN perl -pi -e "s/#listener.security.protocol.map=.*/listener.security.protocol.map=INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT\ninter.broker.listener.name=INTERNAL/" /usr/local/kafka/config/server.properties
|
||||
RUN perl
|
||||
|
||||
# Add directory with TLS support files
|
||||
ADD tls tls
|
||||
|
||||
ADD client_tls client_tls
|
||||
|
||||
# Expose ports:
|
||||
# - 8081: HTTP (coordinator)
|
||||
# - 8082: HTTP (broker)
|
||||
# - 8083: HTTP (historical)
|
||||
# - 8090: HTTP (overlord)
|
||||
# - 8091: HTTP (middlemanager)
|
||||
# - 8081, 8281: HTTP, HTTPS (coordinator)
|
||||
# - 8082, 8282: HTTP, HTTPS (broker)
|
||||
# - 8083, 8283: HTTP, HTTPS (historical)
|
||||
# - 8090, 8290: HTTP, HTTPS (overlord)
|
||||
# - 8091, 8291: HTTP, HTTPS (middlemanager)
|
||||
# - 3306: MySQL
|
||||
# - 2181 2888 3888: ZooKeeper
|
||||
# - 8100 8101 8102 8103 8104 : peon ports
|
||||
EXPOSE 8081
|
||||
EXPOSE 8082
|
||||
EXPOSE 8083
|
||||
EXPOSE 8090
|
||||
EXPOSE 8091
|
||||
# - 8100 8101 8102 8103 8104 8105 : peon ports
|
||||
# - 8300 8301 8302 8303 8304 8305 : peon HTTPS ports
|
||||
EXPOSE 8081 8281
|
||||
EXPOSE 8082 8282
|
||||
EXPOSE 8083 8283
|
||||
EXPOSE 8090 8290
|
||||
EXPOSE 8091 8291
|
||||
EXPOSE 3306
|
||||
EXPOSE 2181 2888 3888
|
||||
EXPOSE 8100 8101 8102 8103 8104
|
||||
EXPOSE 8100 8101 8102 8103 8104 8105
|
||||
EXPOSE 8300 8301 8302 8303 8304 8305
|
||||
EXPOSE 9092 9093
|
||||
|
||||
WORKDIR /var/lib/druid
|
||||
ENTRYPOINT export HOST_IP="$(resolveip -s $HOSTNAME)" && exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||
ENTRYPOINT export HOST_IP="$(resolveip -s $HOSTNAME)" && /tls/generate-server-certs-and-keystores.sh && exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||
|
|
|
@ -36,6 +36,26 @@ command=java
|
|||
-Ddruid.auth.authorizer.basic.type=basic
|
||||
-Ddruid.sql.enable=true
|
||||
-Ddruid.sql.avatica.enable=true
|
||||
-Ddruid.enableTlsPort=true
|
||||
-Ddruid.server.https.keyStorePath=/tls/server.jks
|
||||
-Ddruid.server.https.keyStoreType=jks
|
||||
-Ddruid.server.https.certAlias=druid
|
||||
-Ddruid.server.https.keyManagerPassword=druid123
|
||||
-Ddruid.server.https.keyStorePassword=druid123
|
||||
-Ddruid.server.https.requireClientCertificate=true
|
||||
-Ddruid.server.https.trustStorePath=/tls/truststore.jks
|
||||
-Ddruid.server.https.trustStorePassword=druid123
|
||||
-Ddruid.server.https.trustStoreAlgorithm=PKIX
|
||||
-Ddruid.server.https.validateHostnames=true
|
||||
-Ddruid.server.https.crlPath=/tls/revocations.crl
|
||||
-Ddruid.client.https.trustStoreAlgorithm=PKIX
|
||||
-Ddruid.client.https.protocol=TLSv1.2
|
||||
-Ddruid.client.https.trustStorePath=/tls/truststore.jks
|
||||
-Ddruid.client.https.trustStorePassword=druid123
|
||||
-Ddruid.client.https.keyStorePath=/tls/server.jks
|
||||
-Ddruid.client.https.certAlias=druid
|
||||
-Ddruid.client.https.keyManagerPassword=druid123
|
||||
-Ddruid.client.https.keyStorePassword=druid123
|
||||
-cp /shared/docker/lib/*
|
||||
org.apache.druid.cli.Main server broker
|
||||
redirect_stderr=true
|
||||
|
|
|
@ -9,6 +9,7 @@ command=java
|
|||
-Duser.timezone=UTC
|
||||
-Dfile.encoding=UTF-8
|
||||
-Ddruid.host=%(ENV_HOST_IP)s
|
||||
-Ddruid.server.http.numThreads=100
|
||||
-Ddruid.metadata.storage.type=mysql
|
||||
-Ddruid.metadata.storage.connector.connectURI=jdbc:mysql://druid-metadata-storage/druid
|
||||
-Ddruid.metadata.storage.connector.user=druid
|
||||
|
@ -29,6 +30,26 @@ command=java
|
|||
-Ddruid.auth.authorizers="[\"basic\"]"
|
||||
-Ddruid.auth.authorizer.basic.type=basic
|
||||
-Ddruid.auth.unsecuredPaths="[\"/druid/coordinator/v1/loadqueue\"]"
|
||||
-Ddruid.enableTlsPort=true
|
||||
-Ddruid.server.https.keyStorePath=/tls/server.jks
|
||||
-Ddruid.server.https.keyStoreType=jks
|
||||
-Ddruid.server.https.certAlias=druid
|
||||
-Ddruid.server.https.keyManagerPassword=druid123
|
||||
-Ddruid.server.https.keyStorePassword=druid123
|
||||
-Ddruid.server.https.requireClientCertificate=true
|
||||
-Ddruid.server.https.trustStorePath=/tls/truststore.jks
|
||||
-Ddruid.server.https.trustStorePassword=druid123
|
||||
-Ddruid.server.https.trustStoreAlgorithm=PKIX
|
||||
-Ddruid.server.https.validateHostnames=true
|
||||
-Ddruid.server.https.crlPath=/tls/revocations.crl
|
||||
-Ddruid.client.https.trustStoreAlgorithm=PKIX
|
||||
-Ddruid.client.https.protocol=TLSv1.2
|
||||
-Ddruid.client.https.trustStorePath=/tls/truststore.jks
|
||||
-Ddruid.client.https.trustStorePassword=druid123
|
||||
-Ddruid.client.https.keyStorePath=/tls/server.jks
|
||||
-Ddruid.client.https.certAlias=druid
|
||||
-Ddruid.client.https.keyManagerPassword=druid123
|
||||
-Ddruid.client.https.keyStorePassword=druid123
|
||||
-cp /shared/docker/lib/*
|
||||
org.apache.druid.cli.Main server coordinator
|
||||
redirect_stderr=true
|
||||
|
|
|
@ -32,6 +32,26 @@ command=java
|
|||
-Ddruid.escalator.authorizerName=basic
|
||||
-Ddruid.auth.authorizers="[\"basic\"]"
|
||||
-Ddruid.auth.authorizer.basic.type=basic
|
||||
-Ddruid.enableTlsPort=true
|
||||
-Ddruid.server.https.keyStorePath=/tls/server.jks
|
||||
-Ddruid.server.https.keyStoreType=jks
|
||||
-Ddruid.server.https.certAlias=druid
|
||||
-Ddruid.server.https.keyManagerPassword=druid123
|
||||
-Ddruid.server.https.keyStorePassword=druid123
|
||||
-Ddruid.server.https.requireClientCertificate=true
|
||||
-Ddruid.server.https.trustStorePath=/tls/truststore.jks
|
||||
-Ddruid.server.https.trustStorePassword=druid123
|
||||
-Ddruid.server.https.trustStoreAlgorithm=PKIX
|
||||
-Ddruid.server.https.validateHostnames=true
|
||||
-Ddruid.server.https.crlPath=/tls/revocations.crl
|
||||
-Ddruid.client.https.trustStoreAlgorithm=PKIX
|
||||
-Ddruid.client.https.protocol=TLSv1.2
|
||||
-Ddruid.client.https.trustStorePath=/tls/truststore.jks
|
||||
-Ddruid.client.https.trustStorePassword=druid123
|
||||
-Ddruid.client.https.keyStorePath=/tls/server.jks
|
||||
-Ddruid.client.https.certAlias=druid
|
||||
-Ddruid.client.https.keyManagerPassword=druid123
|
||||
-Ddruid.client.https.keyStorePassword=druid123
|
||||
-cp /shared/docker/lib/*
|
||||
org.apache.druid.cli.Main server historical
|
||||
redirect_stderr=true
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
[program:mysql]
|
||||
command=/usr/bin/pidproxy /var/run/mysqld/mysqld.pid /usr/bin/mysqld_safe
|
||||
--bind-address=0.0.0.0
|
||||
command=/run-mysql.sh
|
||||
user=mysql
|
||||
priority=0
|
||||
stdout_logfile=/shared/logs/mysql.log
|
||||
|
|
|
@ -9,11 +9,12 @@ command=java
|
|||
-Duser.timezone=UTC
|
||||
-Dfile.encoding=UTF-8
|
||||
-Ddruid.host=%(ENV_HOST_IP)s
|
||||
-Ddruid.server.http.numThreads=100
|
||||
-Ddruid.zk.service.host=druid-zookeeper-kafka
|
||||
-Ddruid.worker.capacity=3
|
||||
-Ddruid.indexer.logs.directory=/shared/tasklogs
|
||||
-Ddruid.storage.storageDirectory=/shared/storage
|
||||
-Ddruid.indexer.runner.javaOpts=-server -Xmx256m -Xms256m -XX:NewSize=128m -XX:MaxNewSize=128m -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
|
||||
-Ddruid.indexer.runner.javaOpts="-server -Xmx256m -Xms256m -XX:NewSize=128m -XX:MaxNewSize=128m -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps"
|
||||
-Ddruid.indexer.fork.property.druid.processing.buffer.sizeBytes=25000000
|
||||
-Ddruid.indexer.fork.property.druid.processing.numThreads=1
|
||||
-Ddruid.indexer.fork.server.http.numThreads=100
|
||||
|
@ -35,6 +36,27 @@ command=java
|
|||
-Ddruid.escalator.authorizerName=basic
|
||||
-Ddruid.auth.authorizers="[\"basic\"]"
|
||||
-Ddruid.auth.authorizer.basic.type=basic
|
||||
-Ddruid.enableTlsPort=true
|
||||
-Ddruid.server.https.keyStorePath=/tls/server.jks
|
||||
-Ddruid.server.https.keyStoreType=jks
|
||||
-Ddruid.server.https.certAlias=druid
|
||||
-Ddruid.server.https.keyManagerPassword=druid123
|
||||
-Ddruid.server.https.keyStorePassword=druid123
|
||||
-Ddruid.server.https.requireClientCertificate=true
|
||||
-Ddruid.server.https.trustStorePath=/tls/truststore.jks
|
||||
-Ddruid.server.https.trustStorePassword=druid123
|
||||
-Ddruid.server.https.trustStoreAlgorithm=PKIX
|
||||
-Ddruid.server.https.validateHostnames=true
|
||||
-Ddruid.server.https.crlPath=/tls/revocations.crl
|
||||
-Ddruid.client.https.trustStoreAlgorithm=PKIX
|
||||
-Ddruid.client.https.protocol=TLSv1.2
|
||||
-Ddruid.client.https.trustStorePath=/tls/truststore.jks
|
||||
-Ddruid.client.https.trustStorePassword=druid123
|
||||
-Ddruid.client.https.keyStorePath=/tls/server.jks
|
||||
-Ddruid.client.https.certAlias=druid
|
||||
-Ddruid.client.https.keyManagerPassword=druid123
|
||||
-Ddruid.client.https.keyStorePassword=druid123
|
||||
-Ddruid.startup.logging.logProperties=true
|
||||
-cp /shared/docker/lib/*
|
||||
org.apache.druid.cli.Main server middleManager
|
||||
redirect_stderr=true
|
||||
|
|
|
@ -9,6 +9,7 @@ command=java
|
|||
-Duser.timezone=UTC
|
||||
-Dfile.encoding=UTF-8
|
||||
-Ddruid.host=%(ENV_HOST_IP)s
|
||||
-Ddruid.server.http.numThreads=100
|
||||
-Ddruid.metadata.storage.type=mysql
|
||||
-Ddruid.metadata.storage.connector.connectURI=jdbc:mysql://druid-metadata-storage/druid
|
||||
-Ddruid.metadata.storage.connector.user=druid
|
||||
|
@ -30,6 +31,26 @@ command=java
|
|||
-Ddruid.escalator.authorizerName=basic
|
||||
-Ddruid.auth.authorizers="[\"basic\"]"
|
||||
-Ddruid.auth.authorizer.basic.type=basic
|
||||
-Ddruid.enableTlsPort=true
|
||||
-Ddruid.server.https.keyStorePath=/tls/server.jks
|
||||
-Ddruid.server.https.keyStoreType=jks
|
||||
-Ddruid.server.https.certAlias=druid
|
||||
-Ddruid.server.https.keyManagerPassword=druid123
|
||||
-Ddruid.server.https.keyStorePassword=druid123
|
||||
-Ddruid.server.https.requireClientCertificate=true
|
||||
-Ddruid.server.https.trustStorePath=/tls/truststore.jks
|
||||
-Ddruid.server.https.trustStorePassword=druid123
|
||||
-Ddruid.server.https.trustStoreAlgorithm=PKIX
|
||||
-Ddruid.server.https.validateHostnames=true
|
||||
-Ddruid.server.https.crlPath=/tls/revocations.crl
|
||||
-Ddruid.client.https.trustStoreAlgorithm=PKIX
|
||||
-Ddruid.client.https.protocol=TLSv1.2
|
||||
-Ddruid.client.https.trustStorePath=/tls/truststore.jks
|
||||
-Ddruid.client.https.trustStorePassword=druid123
|
||||
-Ddruid.client.https.keyStorePath=/tls/server.jks
|
||||
-Ddruid.client.https.certAlias=druid
|
||||
-Ddruid.client.https.keyManagerPassword=druid123
|
||||
-Ddruid.client.https.keyStorePassword=druid123
|
||||
-cp /shared/docker/lib/*
|
||||
org.apache.druid.cli.Main server overlord
|
||||
redirect_stderr=true
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
[program:druid-router-no-client-auth-tls]
|
||||
command=java
|
||||
-server
|
||||
-Xmx128m
|
||||
-XX:+UseConcMarkSweepGC
|
||||
-XX:+PrintGCDetails
|
||||
-XX:+PrintGCTimeStamps
|
||||
-Duser.timezone=UTC
|
||||
-Dfile.encoding=UTF-8
|
||||
-Ddruid.host=%(ENV_HOST_IP)s
|
||||
-Ddruid.plaintextPort=8890
|
||||
-Ddruid.tlsPort=9090
|
||||
-Ddruid.zk.service.host=druid-zookeeper-kafka
|
||||
-Ddruid.server.http.numThreads=100
|
||||
-Ddruid.lookup.numLookupLoadingThreads=1
|
||||
-Ddruid.auth.authenticatorChain="[\"basic\"]"
|
||||
-Ddruid.auth.authenticator.basic.type=basic
|
||||
-Ddruid.auth.authenticator.basic.initialAdminPassword=priest
|
||||
-Ddruid.auth.authenticator.basic.initialInternalClientPassword=warlock
|
||||
-Ddruid.auth.authenticator.basic.authorizerName=basic
|
||||
-Ddruid.auth.basic.common.cacheDirectory=/tmp/authCache/router-no-client-auth-tls
|
||||
-Ddruid.escalator.type=basic
|
||||
-Ddruid.escalator.internalClientUsername=druid_system
|
||||
-Ddruid.escalator.internalClientPassword=warlock
|
||||
-Ddruid.escalator.authorizerName=basic
|
||||
-Ddruid.auth.authorizers="[\"basic\"]"
|
||||
-Ddruid.auth.authorizer.basic.type=basic
|
||||
-Ddruid.sql.enable=true
|
||||
-Ddruid.sql.avatica.enable=true
|
||||
-Ddruid.enableTlsPort=true
|
||||
-Ddruid.server.https.keyStorePath=/tls/server.jks
|
||||
-Ddruid.server.https.keyStoreType=jks
|
||||
-Ddruid.server.https.certAlias=druid
|
||||
-Ddruid.server.https.keyManagerPassword=druid123
|
||||
-Ddruid.server.https.keyStorePassword=druid123
|
||||
-Ddruid.server.https.requireClientCertificate=false
|
||||
-Ddruid.server.https.trustStorePath=/tls/truststore.jks
|
||||
-Ddruid.server.https.trustStorePassword=druid123
|
||||
-Ddruid.server.https.trustStoreAlgorithm=PKIX
|
||||
-Ddruid.server.https.validateHostnames=false
|
||||
-Ddruid.client.https.trustStoreAlgorithm=PKIX
|
||||
-Ddruid.client.https.protocol=TLSv1.2
|
||||
-Ddruid.client.https.trustStorePath=/tls/truststore.jks
|
||||
-Ddruid.client.https.trustStorePassword=druid123
|
||||
-Ddruid.client.https.keyStorePath=/tls/server.jks
|
||||
-Ddruid.client.https.certAlias=druid
|
||||
-Ddruid.client.https.keyManagerPassword=druid123
|
||||
-Ddruid.client.https.keyStorePassword=druid123
|
||||
-cp /shared/docker/lib/*
|
||||
org.apache.druid.cli.Main server router
|
||||
redirect_stderr=true
|
||||
priority=100
|
||||
autorestart=false
|
||||
stdout_logfile=/shared/logs/router-no-client-auth-tls.log
|
|
@ -0,0 +1,54 @@
|
|||
[program:druid-router-permissive-tls]
|
||||
command=java
|
||||
-server
|
||||
-Xmx128m
|
||||
-XX:+UseConcMarkSweepGC
|
||||
-XX:+PrintGCDetails
|
||||
-XX:+PrintGCTimeStamps
|
||||
-Duser.timezone=UTC
|
||||
-Dfile.encoding=UTF-8
|
||||
-Ddruid.host=%(ENV_HOST_IP)s
|
||||
-Ddruid.plaintextPort=8889
|
||||
-Ddruid.tlsPort=9089
|
||||
-Ddruid.zk.service.host=druid-zookeeper-kafka
|
||||
-Ddruid.server.http.numThreads=100
|
||||
-Ddruid.lookup.numLookupLoadingThreads=1
|
||||
-Ddruid.auth.authenticatorChain="[\"basic\"]"
|
||||
-Ddruid.auth.authenticator.basic.type=basic
|
||||
-Ddruid.auth.authenticator.basic.initialAdminPassword=priest
|
||||
-Ddruid.auth.authenticator.basic.initialInternalClientPassword=warlock
|
||||
-Ddruid.auth.authenticator.basic.authorizerName=basic
|
||||
-Ddruid.auth.basic.common.cacheDirectory=/tmp/authCache/router-permissive-tls
|
||||
-Ddruid.escalator.type=basic
|
||||
-Ddruid.escalator.internalClientUsername=druid_system
|
||||
-Ddruid.escalator.internalClientPassword=warlock
|
||||
-Ddruid.escalator.authorizerName=basic
|
||||
-Ddruid.auth.authorizers="[\"basic\"]"
|
||||
-Ddruid.auth.authorizer.basic.type=basic
|
||||
-Ddruid.sql.enable=true
|
||||
-Ddruid.sql.avatica.enable=true
|
||||
-Ddruid.enableTlsPort=true
|
||||
-Ddruid.server.https.keyStorePath=/tls/server.jks
|
||||
-Ddruid.server.https.keyStoreType=jks
|
||||
-Ddruid.server.https.certAlias=druid
|
||||
-Ddruid.server.https.keyManagerPassword=druid123
|
||||
-Ddruid.server.https.keyStorePassword=druid123
|
||||
-Ddruid.server.https.requireClientCertificate=true
|
||||
-Ddruid.server.https.trustStorePath=/tls/truststore.jks
|
||||
-Ddruid.server.https.trustStorePassword=druid123
|
||||
-Ddruid.server.https.trustStoreAlgorithm=PKIX
|
||||
-Ddruid.server.https.validateHostnames=false
|
||||
-Ddruid.client.https.trustStoreAlgorithm=PKIX
|
||||
-Ddruid.client.https.protocol=TLSv1.2
|
||||
-Ddruid.client.https.trustStorePath=/tls/truststore.jks
|
||||
-Ddruid.client.https.trustStorePassword=druid123
|
||||
-Ddruid.client.https.keyStorePath=/tls/server.jks
|
||||
-Ddruid.client.https.certAlias=druid
|
||||
-Ddruid.client.https.keyManagerPassword=druid123
|
||||
-Ddruid.client.https.keyStorePassword=druid123
|
||||
-cp /shared/docker/lib/*
|
||||
org.apache.druid.cli.Main server router
|
||||
redirect_stderr=true
|
||||
priority=100
|
||||
autorestart=false
|
||||
stdout_logfile=/shared/logs/router-permissive-tls.log
|
|
@ -25,6 +25,26 @@ command=java
|
|||
-Ddruid.auth.authorizer.basic.type=basic
|
||||
-Ddruid.sql.enable=true
|
||||
-Ddruid.sql.avatica.enable=true
|
||||
-Ddruid.enableTlsPort=true
|
||||
-Ddruid.server.https.keyStorePath=/tls/server.jks
|
||||
-Ddruid.server.https.keyStoreType=jks
|
||||
-Ddruid.server.https.certAlias=druid
|
||||
-Ddruid.server.https.keyManagerPassword=druid123
|
||||
-Ddruid.server.https.keyStorePassword=druid123
|
||||
-Ddruid.server.https.requireClientCertificate=true
|
||||
-Ddruid.server.https.trustStorePath=/tls/truststore.jks
|
||||
-Ddruid.server.https.trustStorePassword=druid123
|
||||
-Ddruid.server.https.trustStoreAlgorithm=PKIX
|
||||
-Ddruid.server.https.validateHostnames=true
|
||||
-Ddruid.server.https.crlPath=/tls/revocations.crl
|
||||
-Ddruid.client.https.trustStoreAlgorithm=PKIX
|
||||
-Ddruid.client.https.protocol=TLSv1.2
|
||||
-Ddruid.client.https.trustStorePath=/tls/truststore.jks
|
||||
-Ddruid.client.https.trustStorePassword=druid123
|
||||
-Ddruid.client.https.keyStorePath=/tls/server.jks
|
||||
-Ddruid.client.https.certAlias=druid
|
||||
-Ddruid.client.https.keyManagerPassword=druid123
|
||||
-Ddruid.client.https.keyStorePassword=druid123
|
||||
-cp /shared/docker/lib/*
|
||||
org.apache.druid.cli.Main server router
|
||||
redirect_stderr=true
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
find /var/lib/mysql -type f -exec touch {} \; && /usr/bin/pidproxy /var/run/mysqld/mysqld.pid /usr/bin/mysqld_safe --bind-address=0.0.0.0
|
|
@ -0,0 +1,21 @@
|
|||
#!/bin/bash -eu
|
||||
|
||||
./docker/tls/generate-root-certs.sh
|
||||
|
||||
mkdir -p client_tls
|
||||
rm -f client_tls/*
|
||||
cp docker/tls/root.key client_tls/root.key
|
||||
cp docker/tls/root.pem client_tls/root.pem
|
||||
cp docker/tls/untrusted_root.key client_tls/untrusted_root.key
|
||||
cp docker/tls/untrusted_root.pem client_tls/untrusted_root.pem
|
||||
cd client_tls
|
||||
|
||||
../docker/tls/generate-expired-client-cert.sh
|
||||
../docker/tls/generate-good-client-cert.sh
|
||||
../docker/tls/generate-incorrect-hostname-client-cert.sh
|
||||
../docker/tls/generate-invalid-intermediate-client-cert.sh
|
||||
../docker/tls/generate-to-be-revoked-client-cert.sh
|
||||
../docker/tls/generate-untrusted-root-client-cert.sh
|
||||
../docker/tls/generate-valid-intermediate-client-cert.sh
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
#!/bin/bash -eu
|
||||
|
||||
export DOCKER_HOST_IP=$(resolveip -s $HOSTNAME)
|
||||
|
||||
cat <<EOT > expired_csr.conf
|
||||
[req]
|
||||
default_bits = 1024
|
||||
prompt = no
|
||||
default_md = sha256
|
||||
req_extensions = req_ext
|
||||
distinguished_name = dn
|
||||
|
||||
[ dn ]
|
||||
C=DR
|
||||
ST=DR
|
||||
L=Druid City
|
||||
O=Druid
|
||||
OU=IntegrationTests
|
||||
emailAddress=integration-test@druid.io
|
||||
CN = localhost
|
||||
|
||||
[ req_ext ]
|
||||
subjectAltName = @alt_names
|
||||
basicConstraints=CA:FALSE,pathlen:0
|
||||
|
||||
[ alt_names ]
|
||||
IP.1 = ${DOCKER_HOST_IP}
|
||||
IP.2 = 127.0.0.1
|
||||
IP.3 = 172.172.172.1
|
||||
DNS.1 = ${HOSTNAME}
|
||||
DNS.2 = localhost
|
||||
EOT
|
||||
|
||||
# Generate a client certificate for this machine
|
||||
openssl genrsa -out expired_client.key 1024 -sha256
|
||||
openssl req -new -out expired_client.csr -key expired_client.key -reqexts req_ext -config expired_csr.conf
|
||||
openssl x509 -req -days -3650 -in expired_client.csr -CA root.pem -CAkey root.key -set_serial 0x11111115 -out expired_client.pem -sha256 -extfile expired_csr.conf -extensions req_ext
|
||||
|
||||
# Create a Java keystore containing the generated certificate
|
||||
openssl pkcs12 -export -in expired_client.pem -inkey expired_client.key -out expired_client.p12 -name expired_client -CAfile root.pem -caname druid-it-root -password pass:druid123
|
||||
keytool -importkeystore -srckeystore expired_client.p12 -srcstoretype PKCS12 -destkeystore expired_client.jks -deststoretype JKS -srcstorepass druid123 -deststorepass druid123
|
|
@ -0,0 +1,44 @@
|
|||
#!/bin/bash -eu
|
||||
|
||||
export DOCKER_HOST_IP=$(resolveip -s $HOSTNAME)
|
||||
|
||||
cat <<EOT > csr.conf
|
||||
[req]
|
||||
default_bits = 1024
|
||||
prompt = no
|
||||
default_md = sha256
|
||||
req_extensions = req_ext
|
||||
distinguished_name = dn
|
||||
|
||||
[ dn ]
|
||||
C=DR
|
||||
ST=DR
|
||||
L=Druid City
|
||||
O=Druid
|
||||
OU=IntegrationTests
|
||||
emailAddress=integration-test@druid.io
|
||||
CN = localhost
|
||||
|
||||
[ req_ext ]
|
||||
subjectAltName = @alt_names
|
||||
basicConstraints=CA:FALSE,pathlen:0
|
||||
|
||||
[ alt_names ]
|
||||
IP.1 = ${DOCKER_HOST_IP}
|
||||
IP.2 = 127.0.0.1
|
||||
IP.3 = 172.172.172.1
|
||||
DNS.1 = ${HOSTNAME}
|
||||
DNS.2 = localhost
|
||||
EOT
|
||||
|
||||
# Generate a client certificate for this machine
|
||||
openssl genrsa -out client.key 1024 -sha256
|
||||
openssl req -new -out client.csr -key client.key -reqexts req_ext -config csr.conf
|
||||
openssl x509 -req -days 3650 -in client.csr -CA root.pem -CAkey root.key -set_serial 0x11111111 -out client.pem -sha256 -extfile csr.conf -extensions req_ext
|
||||
|
||||
# Create a Java keystore containing the generated certificate
|
||||
openssl pkcs12 -export -in client.pem -inkey client.key -out client.p12 -name druid -CAfile root.pem -caname druid-it-root -password pass:druid123
|
||||
keytool -importkeystore -srckeystore client.p12 -srcstoretype PKCS12 -destkeystore client.jks -deststoretype JKS -srcstorepass druid123 -deststorepass druid123
|
||||
|
||||
# Create a Java truststore with the imply test cluster root CA
|
||||
keytool -import -alias druid-it-root -keystore truststore.jks -file root.pem -storepass druid123 -noprompt
|
|
@ -0,0 +1,40 @@
|
|||
#!/bin/bash -eu
|
||||
|
||||
export DOCKER_HOST_IP=$(resolveip -s $HOSTNAME)
|
||||
|
||||
|
||||
# Generate a client cert with an incorrect hostname for testing
|
||||
cat <<EOT > invalid_hostname_csr.conf
|
||||
[req]
|
||||
default_bits = 1024
|
||||
prompt = no
|
||||
default_md = sha256
|
||||
req_extensions = req_ext
|
||||
distinguished_name = dn
|
||||
|
||||
[ dn ]
|
||||
C=DR
|
||||
ST=DR
|
||||
L=Druid City
|
||||
O=Druid
|
||||
OU=IntegrationTests
|
||||
emailAddress=integration-test@druid.io
|
||||
CN = thisisprobablynottherighthostname
|
||||
|
||||
[ req_ext ]
|
||||
subjectAltName = @alt_names
|
||||
basicConstraints=CA:FALSE,pathlen:0
|
||||
|
||||
[ alt_names ]
|
||||
DNS.1 = thisisprobablywrongtoo
|
||||
|
||||
EOT
|
||||
|
||||
openssl genrsa -out invalid_hostname_client.key 1024 -sha256
|
||||
openssl req -new -out invalid_hostname_client.csr -key invalid_hostname_client.key -reqexts req_ext -config invalid_hostname_csr.conf
|
||||
openssl x509 -req -days 3650 -in invalid_hostname_client.csr -CA root.pem -CAkey root.key -set_serial 0x11111112 -out invalid_hostname_client.pem -sha256 -extfile invalid_hostname_csr.conf -extensions req_ext
|
||||
|
||||
# Create a Java keystore containing the generated certificate
|
||||
openssl pkcs12 -export -in invalid_hostname_client.pem -inkey invalid_hostname_client.key -out invalid_hostname_client.p12 -name invalid_hostname_client -CAfile root.pem -caname druid-it-root -password pass:druid123
|
||||
keytool -importkeystore -srckeystore invalid_hostname_client.p12 -srcstoretype PKCS12 -destkeystore invalid_hostname_client.jks -deststoretype JKS -srcstorepass druid123 -deststorepass druid123
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
#!/bin/bash -eu
|
||||
|
||||
export DOCKER_HOST_IP=$(resolveip -s $HOSTNAME)
|
||||
|
||||
cat <<EOT > invalid_ca_intermediate.conf
|
||||
[req]
|
||||
default_bits = 1024
|
||||
prompt = no
|
||||
default_md = sha256
|
||||
req_extensions = req_ext
|
||||
distinguished_name = dn
|
||||
|
||||
[ dn ]
|
||||
C=DR
|
||||
ST=DR
|
||||
L=Druid City
|
||||
O=Druid
|
||||
OU=IntegrationTests
|
||||
emailAddress=bad-intermediate@druid.io
|
||||
CN = badintermediate
|
||||
|
||||
[ req_ext ]
|
||||
subjectAltName = @alt_names
|
||||
basicConstraints=CA:FALSE,pathlen:0
|
||||
|
||||
[ alt_names ]
|
||||
IP.1 = 9.9.9.9
|
||||
EOT
|
||||
|
||||
# Generate a bad intermediate certificate
|
||||
openssl genrsa -out invalid_ca_intermediate.key 1024 -sha256
|
||||
openssl req -new -out invalid_ca_intermediate.csr -key invalid_ca_intermediate.key -reqexts req_ext -config invalid_ca_intermediate.conf
|
||||
openssl x509 -req -days 3650 -in invalid_ca_intermediate.csr -CA root.pem -CAkey root.key -set_serial 0x33333331 -out invalid_ca_intermediate.pem -sha256 -extfile invalid_ca_intermediate.conf -extensions req_ext
|
||||
|
||||
|
||||
cat <<EOT > invalid_ca_client.conf
|
||||
[req]
|
||||
default_bits = 1024
|
||||
prompt = no
|
||||
default_md = sha256
|
||||
req_extensions = req_ext
|
||||
distinguished_name = dn
|
||||
|
||||
[ dn ]
|
||||
C=DR
|
||||
ST=DR
|
||||
L=Druid City
|
||||
O=Druid
|
||||
OU=IntegrationTests
|
||||
emailAddress=basic-constraint-fail@druid.io
|
||||
CN = localhost
|
||||
|
||||
[ req_ext ]
|
||||
subjectAltName = @alt_names
|
||||
basicConstraints=CA:FALSE,pathlen:0
|
||||
|
||||
[ alt_names ]
|
||||
IP.1 = ${DOCKER_HOST_IP}
|
||||
IP.2 = 127.0.0.1
|
||||
IP.3 = 172.172.172.1
|
||||
DNS.1 = ${HOSTNAME}
|
||||
DNS.2 = localhost
|
||||
EOT
|
||||
|
||||
# Generate a client certificate for this machine
|
||||
openssl genrsa -out invalid_ca_client.key 1024 -sha256
|
||||
openssl req -new -out invalid_ca_client.csr -key invalid_ca_client.key -reqexts req_ext -config invalid_ca_client.conf
|
||||
openssl x509 -req -days 3650 -in invalid_ca_client.csr -CA invalid_ca_intermediate.pem -CAkey invalid_ca_intermediate.key -set_serial 0x33333333 -out invalid_ca_client.pem -sha256 -extfile invalid_ca_client.conf -extensions req_ext
|
||||
|
||||
# Append the signing cert
|
||||
printf "\n" >> invalid_ca_client.pem
|
||||
cat invalid_ca_intermediate.pem >> invalid_ca_client.pem
|
||||
|
||||
# Create a Java keystore containing the generated certificate
|
||||
openssl pkcs12 -export -in invalid_ca_client.pem -inkey invalid_ca_client.key -out invalid_ca_client.p12 -name invalid_ca_client -CAfile invalid_ca_intermediate.pem -caname druid-it-root -password pass:druid123
|
||||
keytool -importkeystore -srckeystore invalid_ca_client.p12 -srcstoretype PKCS12 -destkeystore invalid_ca_client.jks -deststoretype JKS -srcstorepass druid123 -deststorepass druid123
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash -eu
|
||||
|
||||
rm -f root.key
|
||||
rm -f untrusted_root.key
|
||||
rm -f root.pem
|
||||
rm -f untrusted_root.pem
|
||||
|
||||
openssl genrsa -out docker/tls/root.key 4096
|
||||
openssl genrsa -out docker/tls/untrusted_root.key 4096
|
||||
|
||||
openssl req -config docker/tls/root.cnf -key docker/tls/root.key -new -x509 -days 3650 -sha256 -extensions v3_ca -out docker/tls/root.pem
|
||||
openssl req -config docker/tls/root.cnf -key docker/tls/untrusted_root.key -new -x509 -days 3650 -sha256 -extensions v3_ca -out docker/tls/untrusted_root.pem
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
#!/bin/bash -eu
|
||||
|
||||
cd /tls
|
||||
|
||||
rm -f cert_db.txt
|
||||
touch cert_db.txt
|
||||
|
||||
export DOCKER_IP=$(cat /docker_ip)
|
||||
export MY_HOSTNAME=$(hostname)
|
||||
export MY_IP=$(hostname -i)
|
||||
|
||||
cat <<EOT > csr.conf
|
||||
[req]
|
||||
default_bits = 1024
|
||||
prompt = no
|
||||
default_md = sha256
|
||||
req_extensions = req_ext
|
||||
distinguished_name = dn
|
||||
|
||||
[ dn ]
|
||||
C=DR
|
||||
ST=DR
|
||||
L=Druid City
|
||||
O=Druid
|
||||
OU=IntegrationTests
|
||||
emailAddress=integration-test@druid.io
|
||||
CN = ${MY_IP}
|
||||
|
||||
[ req_ext ]
|
||||
subjectAltName = @alt_names
|
||||
basicConstraints=CA:FALSE,pathlen:0
|
||||
|
||||
[ alt_names ]
|
||||
IP.1 = ${DOCKER_IP}
|
||||
IP.2 = ${MY_IP}
|
||||
IP.3 = 127.0.0.1
|
||||
DNS.1 = ${MY_HOSTNAME}
|
||||
DNS.2 = localhost
|
||||
|
||||
EOT
|
||||
|
||||
# Generate a server certificate for this machine
|
||||
openssl genrsa -out server.key 1024 -sha256
|
||||
openssl req -new -out server.csr -key server.key -reqexts req_ext -config csr.conf
|
||||
openssl x509 -req -days 3650 -in server.csr -CA root.pem -CAkey root.key -set_serial 0x22222222 -out server.pem -sha256 -extfile csr.conf -extensions req_ext
|
||||
|
||||
# Create a Java keystore containing the generated certificate
|
||||
openssl pkcs12 -export -in server.pem -inkey server.key -out server.p12 -name druid -CAfile root.pem -caname druid-it-root -password pass:druid123
|
||||
keytool -importkeystore -srckeystore server.p12 -srcstoretype PKCS12 -destkeystore server.jks -deststoretype JKS -srcstorepass druid123 -deststorepass druid123
|
||||
|
||||
# Create a Java truststore with the imply test cluster root CA
|
||||
keytool -import -alias druid-it-root -keystore truststore.jks -file root.pem -storepass druid123 -noprompt
|
||||
|
||||
# Revoke one of the client certs
|
||||
openssl ca -revoke /client_tls/revoked_client.pem -config root.cnf -cert root.pem -keyfile root.key
|
||||
|
||||
# Create the CRL
|
||||
openssl ca -gencrl -config root.cnf -cert root.pem -keyfile root.key -out /tls/revocations.crl
|
||||
|
||||
# Generate empty CRLs for the intermediate cert test case
|
||||
rm -f cert_db2.txt
|
||||
touch cert_db2.txt
|
||||
openssl ca -gencrl -config root2.cnf -cert /client_tls/ca_intermediate.pem -keyfile /client_tls/ca_intermediate.key -out /tls/empty-revocations-intermediate.crl
|
||||
|
||||
# Append CRLs
|
||||
cat empty-revocations-intermediate.crl >> revocations.crl
|
|
@ -0,0 +1,43 @@
|
|||
#!/bin/bash -eu
|
||||
|
||||
export DOCKER_HOST_IP=$(resolveip -s $HOSTNAME)
|
||||
|
||||
# Generate a client cert that will be revoked
|
||||
cat <<EOT > revoked_csr.conf
|
||||
[req]
|
||||
default_bits = 1024
|
||||
prompt = no
|
||||
default_md = sha256
|
||||
req_extensions = req_ext
|
||||
distinguished_name = dn
|
||||
|
||||
[ dn ]
|
||||
C=DR
|
||||
ST=DR
|
||||
L=Druid City
|
||||
O=Druid
|
||||
OU=RevokedIntegrationTests
|
||||
emailAddress=revoked-it-cert@druid.io
|
||||
CN = localhost
|
||||
|
||||
[ req_ext ]
|
||||
subjectAltName = @alt_names
|
||||
basicConstraints=CA:FALSE,pathlen:0
|
||||
|
||||
[ alt_names ]
|
||||
IP.1 = ${DOCKER_HOST_IP}
|
||||
IP.2 = 127.0.0.1
|
||||
IP.3 = 172.172.172.1
|
||||
DNS.1 = ${HOSTNAME}
|
||||
DNS.2 = localhost
|
||||
|
||||
EOT
|
||||
|
||||
# Generate a client certificate for this machine
|
||||
openssl genrsa -out revoked_client.key 1024 -sha256
|
||||
openssl req -new -out revoked_client.csr -key revoked_client.key -reqexts req_ext -config revoked_csr.conf
|
||||
openssl x509 -req -days 3650 -in revoked_client.csr -CA root.pem -CAkey root.key -set_serial 0x11111113 -out revoked_client.pem -sha256 -extfile csr.conf -extensions req_ext
|
||||
|
||||
# Create a Java keystore containing the generated certificate
|
||||
openssl pkcs12 -export -in revoked_client.pem -inkey revoked_client.key -out revoked_client.p12 -name revoked_druid -CAfile root.pem -caname druid-it-root -password pass:druid123
|
||||
keytool -importkeystore -srckeystore revoked_client.p12 -srcstoretype PKCS12 -destkeystore revoked_client.jks -deststoretype JKS -srcstorepass druid123 -deststorepass druid123
|
|
@ -0,0 +1,42 @@
|
|||
#!/bin/bash -eu
|
||||
|
||||
export DOCKER_HOST_IP=$(resolveip -s $HOSTNAME)
|
||||
|
||||
cat <<EOT > csr_another_root.conf
|
||||
[req]
|
||||
default_bits = 1024
|
||||
prompt = no
|
||||
default_md = sha256
|
||||
req_extensions = req_ext
|
||||
distinguished_name = dn
|
||||
|
||||
[ dn ]
|
||||
C=DR
|
||||
ST=DR
|
||||
L=Druid City
|
||||
O=Druid
|
||||
OU=IntegrationTests
|
||||
emailAddress=integration-test@druid.io
|
||||
CN = localhost
|
||||
|
||||
[ req_ext ]
|
||||
subjectAltName = @alt_names
|
||||
basicConstraints=CA:FALSE,pathlen:0
|
||||
|
||||
[ alt_names ]
|
||||
IP.1 = ${DOCKER_HOST_IP}
|
||||
IP.2 = 127.0.0.1
|
||||
IP.3 = 172.172.172.1
|
||||
DNS.1 = ${HOSTNAME}
|
||||
DNS.2 = localhost
|
||||
EOT
|
||||
|
||||
# Generate a client certificate for this machine
|
||||
openssl genrsa -out client_another_root.key 1024 -sha256
|
||||
openssl req -new -out client_another_root.csr -key client_another_root.key -reqexts req_ext -config csr_another_root.conf
|
||||
openssl x509 -req -days 3650 -in client_another_root.csr -CA untrusted_root.pem -CAkey untrusted_root.key -set_serial 0x11111114 -out client_another_root.pem -sha256 -extfile csr_another_root.conf -extensions req_ext
|
||||
|
||||
# Create a Java keystore containing the generated certificate
|
||||
openssl pkcs12 -export -in client_another_root.pem -inkey client_another_root.key -out client_another_root.p12 -name druid_another_root -CAfile untrusted_root.pem -caname druid-it-untrusted-root -password pass:druid123
|
||||
keytool -importkeystore -srckeystore client_another_root.p12 -srcstoretype PKCS12 -destkeystore client_another_root.jks -deststoretype JKS -srcstorepass druid123 -deststorepass druid123
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
#!/bin/bash -eu
|
||||
|
||||
export DOCKER_HOST_IP=$(resolveip -s $HOSTNAME)
|
||||
|
||||
cat <<EOT > ca_intermediate.conf
|
||||
[req]
|
||||
default_bits = 1024
|
||||
prompt = no
|
||||
default_md = sha256
|
||||
req_extensions = req_ext
|
||||
distinguished_name = dn
|
||||
|
||||
[ dn ]
|
||||
C=DR
|
||||
ST=DR
|
||||
L=Druid City
|
||||
O=Druid
|
||||
OU=IntegrationTests
|
||||
emailAddress=intermediate@druid.io
|
||||
CN = intermediate
|
||||
|
||||
[ req_ext ]
|
||||
subjectAltName = @alt_names
|
||||
basicConstraints=CA:TRUE,pathlen:1
|
||||
|
||||
[ alt_names ]
|
||||
IP.1 = 9.9.9.9
|
||||
EOT
|
||||
|
||||
# Generate an intermediate certificate
|
||||
openssl genrsa -out ca_intermediate.key 1024 -sha256
|
||||
openssl req -new -out ca_intermediate.csr -key ca_intermediate.key -reqexts req_ext -config ca_intermediate.conf
|
||||
openssl x509 -req -days 3650 -in ca_intermediate.csr -CA root.pem -CAkey root.key -set_serial 0x33333332 -out ca_intermediate.pem -sha256 -extfile ca_intermediate.conf -extensions req_ext
|
||||
|
||||
|
||||
cat <<EOT > intermediate_ca_client.conf
|
||||
[req]
|
||||
default_bits = 1024
|
||||
prompt = no
|
||||
default_md = sha256
|
||||
req_extensions = req_ext
|
||||
distinguished_name = dn
|
||||
|
||||
[ dn ]
|
||||
C=DR
|
||||
ST=DR
|
||||
L=Druid City
|
||||
O=Druid
|
||||
OU=IntegrationTests
|
||||
emailAddress=intermediate-client@druid.io
|
||||
CN = localhost
|
||||
|
||||
[ req_ext ]
|
||||
subjectAltName = @alt_names
|
||||
basicConstraints=CA:FALSE,pathlen:0
|
||||
|
||||
[ alt_names ]
|
||||
IP.1 = ${DOCKER_HOST_IP}
|
||||
IP.2 = 127.0.0.1
|
||||
IP.3 = 172.172.172.1
|
||||
DNS.1 = ${HOSTNAME}
|
||||
DNS.2 = localhost
|
||||
EOT
|
||||
|
||||
# Generate a client certificate for this machine
|
||||
openssl genrsa -out intermediate_ca_client.key 1024 -sha256
|
||||
openssl req -new -out intermediate_ca_client.csr -key intermediate_ca_client.key -reqexts req_ext -config intermediate_ca_client.conf
|
||||
openssl x509 -req -days 3650 -in intermediate_ca_client.csr -CA ca_intermediate.pem -CAkey ca_intermediate.key -set_serial 0x33333333 -out intermediate_ca_client.pem -sha256 -extfile intermediate_ca_client.conf -extensions req_ext
|
||||
|
||||
# Append the signing cert
|
||||
printf "\n" >> intermediate_ca_client.pem
|
||||
cat ca_intermediate.pem >> intermediate_ca_client.pem
|
||||
|
||||
# Create a Java keystore containing the generated certificate
|
||||
openssl pkcs12 -export -in intermediate_ca_client.pem -inkey intermediate_ca_client.key -out intermediate_ca_client.p12 -name intermediate_ca_client -CAfile ca_intermediate.pem -caname druid-it-root -password pass:druid123
|
||||
keytool -importkeystore -srckeystore intermediate_ca_client.p12 -srcstoretype PKCS12 -destkeystore intermediate_ca_client.jks -deststoretype JKS -srcstorepass druid123 -deststorepass druid123
|
|
@ -0,0 +1,35 @@
|
|||
[ ca ]
|
||||
default_ca = CA_default
|
||||
|
||||
[ CA_default ]
|
||||
database = /tls/cert_db.txt
|
||||
x509_extensions = usr_cert
|
||||
name_opt = ca_default
|
||||
cert_opt = ca_default
|
||||
default_days = 365
|
||||
default_crl_days= 30
|
||||
default_md = default
|
||||
preserve = no
|
||||
policy = policy_match
|
||||
|
||||
[req]
|
||||
default_bits = 4096
|
||||
prompt = no
|
||||
default_md = sha256
|
||||
req_extensions = v3_ca
|
||||
distinguished_name = dn
|
||||
|
||||
[ dn ]
|
||||
C=DR
|
||||
ST=DR
|
||||
L=Druid City
|
||||
O=Druid
|
||||
OU=IntegrationTests
|
||||
emailAddress=integration-test@druid.io
|
||||
CN = itroot
|
||||
|
||||
[ v3_ca ]
|
||||
subjectKeyIdentifier = hash
|
||||
authorityKeyIdentifier = keyid:always,issuer
|
||||
basicConstraints = critical, CA:true
|
||||
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
|
|
@ -0,0 +1,13 @@
|
|||
[ ca ]
|
||||
default_ca = CA_default
|
||||
|
||||
[ CA_default ]
|
||||
database = /tls/cert_db2.txt
|
||||
x509_extensions = usr_cert
|
||||
name_opt = ca_default
|
||||
cert_opt = ca_default
|
||||
default_days = 365
|
||||
default_crl_days= 30
|
||||
default_md = default
|
||||
preserve = no
|
||||
policy = policy_match
|
|
@ -88,6 +88,11 @@
|
|||
<artifactId>druid-basic-security</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.druid.extensions</groupId>
|
||||
<artifactId>simple-client-sslcontext</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.druid</groupId>
|
||||
<artifactId>druid-services</artifactId>
|
||||
|
@ -227,6 +232,12 @@
|
|||
-Ddruid.test.config.dockerIp=${env.DOCKER_IP}
|
||||
-Ddruid.test.config.hadoopDir=${env.HADOOP_DIR}
|
||||
-Ddruid.zk.service.host=${env.DOCKER_IP}
|
||||
-Ddruid.client.https.trustStorePath=client_tls/truststore.jks
|
||||
-Ddruid.client.https.trustStorePassword=druid123
|
||||
-Ddruid.client.https.keyStorePath=client_tls/client.jks
|
||||
-Ddruid.client.https.certAlias=druid
|
||||
-Ddruid.client.https.keyManagerPassword=druid123
|
||||
-Ddruid.client.https.keyStorePassword=druid123
|
||||
</argLine>
|
||||
<suiteXmlFiles>
|
||||
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
|
||||
|
@ -276,6 +287,12 @@
|
|||
-Dfile.encoding=UTF-8
|
||||
-Ddruid.test.config.type=configFile
|
||||
-Ddruid.test.config.configFile=${env.CONFIG_FILE}
|
||||
-Ddruid.client.https.trustStorePath=client_tls/truststore.jks
|
||||
-Ddruid.client.https.trustStorePassword=druid123
|
||||
-Ddruid.client.https.keyStorePath=client_tls/client.jks
|
||||
-Ddruid.client.https.certAlias=druid
|
||||
-Ddruid.client.https.keyManagerPassword=druid123
|
||||
-Ddruid.client.https.keyStorePassword=druid123
|
||||
</argLine>
|
||||
<suiteXmlFiles>
|
||||
<suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
|
||||
|
|
|
@ -15,12 +15,14 @@
|
|||
# limitations under the License.
|
||||
|
||||
# cleanup
|
||||
for node in druid-historical druid-coordinator druid-overlord druid-router druid-broker druid-middlemanager druid-zookeeper-kafka druid-metadata-storage;
|
||||
for node in druid-historical druid-coordinator druid-overlord druid-router druid-router-permissive-tls druid-router-no-client-auth-tls druid-broker druid-middlemanager druid-zookeeper-kafka druid-metadata-storage;
|
||||
do
|
||||
docker stop $node
|
||||
docker rm $node
|
||||
done
|
||||
|
||||
docker network rm druid-it-net
|
||||
|
||||
# environment variables
|
||||
DIR=$(cd $(dirname $0) && pwd)
|
||||
DOCKERDIR=$DIR/docker
|
||||
|
@ -31,6 +33,11 @@ RESOURCEDIR=$DIR/src/test/resources
|
|||
# so docker IP addr will be known during docker build
|
||||
echo ${DOCKER_IP:=127.0.0.1} > $DOCKERDIR/docker_ip
|
||||
|
||||
# setup client keystore
|
||||
./docker/tls/generate-client-certs-and-keystores.sh
|
||||
rm -rf docker/client_tls
|
||||
cp -r client_tls docker/client_tls
|
||||
|
||||
# Make directories if they dont exist
|
||||
mkdir -p $SHARED_DIR/logs
|
||||
mkdir -p $SHARED_DIR/tasklogs
|
||||
|
@ -40,29 +47,37 @@ rm -rf $SHARED_DIR/docker
|
|||
cp -R docker $SHARED_DIR/docker
|
||||
mvn -B dependency:copy-dependencies -DoutputDirectory=$SHARED_DIR/docker/lib
|
||||
|
||||
docker network create --subnet=172.172.172.0/24 druid-it-net
|
||||
|
||||
# Build Druid Cluster Image
|
||||
docker build -t druid/cluster $SHARED_DIR/docker
|
||||
|
||||
# Start zookeeper and kafka
|
||||
docker run -d --privileged --name druid-zookeeper-kafka -p 2181:2181 -p 9092:9092 -p 9093:9093 -v $SHARED_DIR:/shared -v $DOCKERDIR/zookeeper.conf:$SUPERVISORDIR/zookeeper.conf -v $DOCKERDIR/kafka.conf:$SUPERVISORDIR/kafka.conf druid/cluster
|
||||
docker run -d --privileged --net druid-it-net --ip 172.172.172.2 --name druid-zookeeper-kafka -p 2181:2181 -p 9092:9092 -p 9093:9093 -v $SHARED_DIR:/shared -v $DOCKERDIR/zookeeper.conf:$SUPERVISORDIR/zookeeper.conf -v $DOCKERDIR/kafka.conf:$SUPERVISORDIR/kafka.conf druid/cluster
|
||||
|
||||
# Start MYSQL
|
||||
docker run -d --privileged --name druid-metadata-storage -v $SHARED_DIR:/shared -v $DOCKERDIR/metadata-storage.conf:$SUPERVISORDIR/metadata-storage.conf druid/cluster
|
||||
docker run -d --privileged --net druid-it-net --ip 172.172.172.3 --name druid-metadata-storage -v $SHARED_DIR:/shared -v $DOCKERDIR/metadata-storage.conf:$SUPERVISORDIR/metadata-storage.conf druid/cluster
|
||||
|
||||
# Start Overlord
|
||||
docker run -d --privileged --name druid-overlord -p 8090:8090 -v $SHARED_DIR:/shared -v $DOCKERDIR/overlord.conf:$SUPERVISORDIR/overlord.conf --link druid-metadata-storage:druid-metadata-storage --link druid-zookeeper-kafka:druid-zookeeper-kafka druid/cluster
|
||||
docker run -d --privileged --net druid-it-net --ip 172.172.172.4 --name druid-overlord -p 8090:8090 -p 8290:8290 -v $SHARED_DIR:/shared -v $DOCKERDIR/overlord.conf:$SUPERVISORDIR/overlord.conf --link druid-metadata-storage:druid-metadata-storage --link druid-zookeeper-kafka:druid-zookeeper-kafka druid/cluster
|
||||
|
||||
# Start Coordinator
|
||||
docker run -d --privileged --name druid-coordinator -p 8081:8081 -v $SHARED_DIR:/shared -v $DOCKERDIR/coordinator.conf:$SUPERVISORDIR/coordinator.conf --link druid-overlord:druid-overlord --link druid-metadata-storage:druid-metadata-storage --link druid-zookeeper-kafka:druid-zookeeper-kafka druid/cluster
|
||||
docker run -d --privileged --net druid-it-net --ip 172.172.172.5 --name druid-coordinator -p 8081:8081 -p 8281:8281 -v $SHARED_DIR:/shared -v $DOCKERDIR/coordinator.conf:$SUPERVISORDIR/coordinator.conf --link druid-overlord:druid-overlord --link druid-metadata-storage:druid-metadata-storage --link druid-zookeeper-kafka:druid-zookeeper-kafka druid/cluster
|
||||
|
||||
# Start Historical
|
||||
docker run -d --privileged --name druid-historical -p 8083:8083 -v $SHARED_DIR:/shared -v $DOCKERDIR/historical.conf:$SUPERVISORDIR/historical.conf --link druid-zookeeper-kafka:druid-zookeeper-kafka druid/cluster
|
||||
docker run -d --privileged --net druid-it-net --ip 172.172.172.6 --name druid-historical -p 8083:8083 -p 8283:8283 -v $SHARED_DIR:/shared -v $DOCKERDIR/historical.conf:$SUPERVISORDIR/historical.conf --link druid-zookeeper-kafka:druid-zookeeper-kafka druid/cluster
|
||||
|
||||
# Start Middlemanger
|
||||
docker run -d --privileged --name druid-middlemanager -p 8091:8091 -p 8100:8100 -p 8101:8101 -p 8102:8102 -p 8103:8103 -p 8104:8104 -p 8105:8105 -v $RESOURCEDIR:/resources -v $SHARED_DIR:/shared -v $DOCKERDIR/middlemanager.conf:$SUPERVISORDIR/middlemanager.conf --link druid-zookeeper-kafka:druid-zookeeper-kafka --link druid-overlord:druid-overlord druid/cluster
|
||||
docker run -d --privileged --net druid-it-net --ip 172.172.172.7 --name druid-middlemanager -p 8091:8091 -p 8291:8291 -p 8100:8100 -p 8101:8101 -p 8102:8102 -p 8103:8103 -p 8104:8104 -p 8105:8105 -p 8300:8300 -p 8301:8301 -p 8302:8302 -p 8303:8303 -p 8304:8304 -p 8305:8305 -v $RESOURCEDIR:/resources -v $SHARED_DIR:/shared -v $DOCKERDIR/middlemanager.conf:$SUPERVISORDIR/middlemanager.conf --link druid-zookeeper-kafka:druid-zookeeper-kafka --link druid-overlord:druid-overlord druid/cluster
|
||||
|
||||
# Start Broker
|
||||
docker run -d --privileged --name druid-broker -p 8082:8082 -v $SHARED_DIR:/shared -v $DOCKERDIR/broker.conf:$SUPERVISORDIR/broker.conf --link druid-zookeeper-kafka:druid-zookeeper-kafka --link druid-middlemanager:druid-middlemanager --link druid-historical:druid-historical druid/cluster
|
||||
docker run -d --privileged --net druid-it-net --ip 172.172.172.8 --name druid-broker -p 8082:8082 -p 8282:8282 -v $SHARED_DIR:/shared -v $DOCKERDIR/broker.conf:$SUPERVISORDIR/broker.conf --link druid-zookeeper-kafka:druid-zookeeper-kafka --link druid-middlemanager:druid-middlemanager --link druid-historical:druid-historical druid/cluster
|
||||
|
||||
# Start Router
|
||||
docker run -d --privileged --name druid-router -p 8888:8888 -v $SHARED_DIR:/shared -v $DOCKERDIR/router.conf:$SUPERVISORDIR/router.conf --link druid-zookeeper-kafka:druid-zookeeper-kafka --link druid-coordinator:druid-coordinator --link druid-broker:druid-broker druid/cluster
|
||||
# Start Router
|
||||
docker run -d --privileged --net druid-it-net --ip 172.172.172.9 --name druid-router -p 8888:8888 -p 9088:9088 -v $SHARED_DIR:/shared -v $DOCKERDIR/router.conf:$SUPERVISORDIR/router.conf --link druid-zookeeper-kafka:druid-zookeeper-kafka --link druid-coordinator:druid-coordinator --link druid-broker:druid-broker druid/cluster
|
||||
|
||||
# Start Router with permissive TLS settings (client auth enabled, no hostname verification, no revocation check)
|
||||
docker run -d --privileged --net druid-it-net --ip 172.172.172.10 --name druid-router-permissive-tls -p 8889:8889 -p 9089:9089 -v $SHARED_DIR:/shared -v $DOCKERDIR/router-permissive-tls.conf:$SUPERVISORDIR/router-permissive-tls.conf --link druid-zookeeper-kafka:druid-zookeeper-kafka --link druid-coordinator:druid-coordinator --link druid-broker:druid-broker druid/cluster
|
||||
|
||||
# Start Router with TLS but no client auth
|
||||
docker run -d --privileged --net druid-it-net --ip 172.172.172.11 --name druid-router-no-client-auth-tls -p 8890:8890 -p 9090:9090 -v $SHARED_DIR:/shared -v $DOCKERDIR/router-no-client-auth-tls.conf:$SUPERVISORDIR/router-no-client-auth-tls.conf --link druid-zookeeper-kafka:druid-zookeeper-kafka --link druid-coordinator:druid-coordinator --link druid-broker:druid-broker druid/cluster
|
||||
|
|
|
@ -38,6 +38,15 @@ public class ConfigFileConfigProvider implements IntegrationTestingConfigProvide
|
|||
private String historicalUrl;
|
||||
private String coordinatorUrl;
|
||||
private String indexerUrl;
|
||||
private String permissiveRouterUrl;
|
||||
private String noClientAuthRouterUrl;
|
||||
private String routerTLSUrl;
|
||||
private String brokerTLSUrl;
|
||||
private String historicalTLSUrl;
|
||||
private String coordinatorTLSUrl;
|
||||
private String indexerTLSUrl;
|
||||
private String permissiveRouterTLSUrl;
|
||||
private String noClientAuthRouterTLSUrl;
|
||||
private String middleManagerHost;
|
||||
private String zookeeperHosts; // comma-separated list of host:port
|
||||
private String kafkaHost;
|
||||
|
@ -70,25 +79,89 @@ public class ConfigFileConfigProvider implements IntegrationTestingConfigProvide
|
|||
routerUrl = StringUtils.format("http://%s:%s", routerHost, props.get("router_port"));
|
||||
}
|
||||
}
|
||||
routerTLSUrl = props.get("router_tls_url");
|
||||
if (routerTLSUrl == null) {
|
||||
String routerHost = props.get("router_host");
|
||||
if (null != routerHost) {
|
||||
routerTLSUrl = StringUtils.format("https://%s:%s", routerHost, props.get("router_tls_port"));
|
||||
}
|
||||
}
|
||||
permissiveRouterUrl = props.get("router_permissive_url");
|
||||
if (permissiveRouterUrl == null) {
|
||||
String permissiveRouterHost = props.get("router_permissive_host");
|
||||
if (null != permissiveRouterHost) {
|
||||
permissiveRouterUrl = StringUtils.format("http://%s:%s", permissiveRouterHost, props.get("router_permissive_port"));
|
||||
}
|
||||
}
|
||||
permissiveRouterTLSUrl = props.get("router_permissive_tls_url");
|
||||
if (permissiveRouterTLSUrl == null) {
|
||||
String permissiveRouterHost = props.get("router_permissive_host");
|
||||
if (null != permissiveRouterHost) {
|
||||
permissiveRouterTLSUrl = StringUtils.format("https://%s:%s", permissiveRouterHost, props.get("router_permissive_tls_port"));
|
||||
}
|
||||
}
|
||||
noClientAuthRouterUrl = props.get("router_no_client_auth_url");
|
||||
if (noClientAuthRouterUrl == null) {
|
||||
String noClientAuthRouterHost = props.get("router_no_client_auth_host");
|
||||
if (null != noClientAuthRouterHost) {
|
||||
noClientAuthRouterUrl = StringUtils.format("http://%s:%s", noClientAuthRouterHost, props.get("router_no_client_auth_port"));
|
||||
}
|
||||
}
|
||||
noClientAuthRouterTLSUrl = props.get("router_no_client_auth_tls_url");
|
||||
if (noClientAuthRouterTLSUrl == null) {
|
||||
String noClientAuthRouterHost = props.get("router_no_client_auth_host");
|
||||
if (null != noClientAuthRouterHost) {
|
||||
noClientAuthRouterTLSUrl = StringUtils.format("https://%s:%s", noClientAuthRouterHost, props.get("router_no_client_auth_tls_port"));
|
||||
}
|
||||
}
|
||||
brokerUrl = props.get("broker_url");
|
||||
if (brokerUrl == null) {
|
||||
brokerUrl = StringUtils.format("http://%s:%s", props.get("broker_host"), props.get("broker_port"));
|
||||
}
|
||||
|
||||
brokerTLSUrl = props.get("broker_tls_url");
|
||||
if (brokerTLSUrl == null) {
|
||||
String brokerHost = props.get("broker_host");
|
||||
if (null != brokerHost) {
|
||||
brokerTLSUrl = StringUtils.format("https://%s:%s", brokerHost, props.get("broker_tls_port"));
|
||||
}
|
||||
}
|
||||
|
||||
historicalUrl = props.get("historical_url");
|
||||
if (historicalUrl == null) {
|
||||
historicalUrl = StringUtils.format("http://%s:%s", props.get("historical_host"), props.get("historical_port"));
|
||||
}
|
||||
historicalTLSUrl = props.get("historical_tls_url");
|
||||
if (historicalTLSUrl == null) {
|
||||
String historicalHost = props.get("historical_host");
|
||||
if (null != historicalHost) {
|
||||
historicalTLSUrl = StringUtils.format("https://%s:%s", historicalHost, props.get("historical_tls_port"));
|
||||
}
|
||||
}
|
||||
|
||||
coordinatorUrl = props.get("coordinator_url");
|
||||
if (coordinatorUrl == null) {
|
||||
coordinatorUrl = StringUtils.format("http://%s:%s", props.get("coordinator_host"), props.get("coordinator_port"));
|
||||
}
|
||||
coordinatorTLSUrl = props.get("coordinator_tls_url");
|
||||
if (coordinatorTLSUrl == null) {
|
||||
String coordinatorHost = props.get("coordinator_host");
|
||||
if (null != coordinatorHost) {
|
||||
coordinatorTLSUrl = StringUtils.format("https://%s:%s", coordinatorHost, props.get("coordinator_tls_port"));
|
||||
}
|
||||
}
|
||||
|
||||
indexerUrl = props.get("indexer_url");
|
||||
if (indexerUrl == null) {
|
||||
indexerUrl = StringUtils.format("http://%s:%s", props.get("indexer_host"), props.get("indexer_port"));
|
||||
}
|
||||
indexerTLSUrl = props.get("indexer_tls_url");
|
||||
if (indexerTLSUrl == null) {
|
||||
String indexerHost = props.get("indexer_host");
|
||||
if (null != indexerHost) {
|
||||
indexerTLSUrl = StringUtils.format("https://%s:%s", indexerHost, props.get("indexer_tls_port"));
|
||||
}
|
||||
}
|
||||
|
||||
middleManagerHost = props.get("middlemanager_host");
|
||||
|
||||
zookeeperHosts = props.get("zookeeper_hosts");
|
||||
|
@ -98,10 +171,11 @@ public class ConfigFileConfigProvider implements IntegrationTestingConfigProvide
|
|||
|
||||
password = props.get("password");
|
||||
|
||||
LOG.info("router: [%s]", routerUrl);
|
||||
LOG.info("broker: [%s]", brokerUrl);
|
||||
LOG.info("coordinator: [%s]", coordinatorUrl);
|
||||
LOG.info("overlord: [%s]", indexerUrl);
|
||||
LOG.info("router: [%s], [%s]", routerUrl, routerTLSUrl);
|
||||
LOG.info("broker: [%s], [%s]", brokerUrl, brokerTLSUrl);
|
||||
LOG.info("historical: [%s], [%s]", historicalUrl, historicalTLSUrl);
|
||||
LOG.info("coordinator: [%s], [%s]", coordinatorUrl, coordinatorTLSUrl);
|
||||
LOG.info("overlord: [%s], [%s]", indexerUrl, indexerTLSUrl);
|
||||
LOG.info("middle manager: [%s]", middleManagerHost);
|
||||
LOG.info("zookeepers: [%s]", zookeeperHosts);
|
||||
LOG.info("kafka: [%s]", kafkaHost);
|
||||
|
@ -120,30 +194,84 @@ public class ConfigFileConfigProvider implements IntegrationTestingConfigProvide
|
|||
return coordinatorUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCoordinatorTLSUrl()
|
||||
{
|
||||
return coordinatorTLSUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIndexerUrl()
|
||||
{
|
||||
return indexerUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIndexerTLSUrl()
|
||||
{
|
||||
return indexerTLSUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRouterUrl()
|
||||
{
|
||||
return routerUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRouterTLSUrl()
|
||||
{
|
||||
return routerTLSUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPermissiveRouterUrl()
|
||||
{
|
||||
return permissiveRouterUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPermissiveRouterTLSUrl()
|
||||
{
|
||||
return permissiveRouterTLSUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNoClientAuthRouterUrl()
|
||||
{
|
||||
return noClientAuthRouterUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNoClientAuthRouterTLSUrl()
|
||||
{
|
||||
return noClientAuthRouterTLSUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBrokerUrl()
|
||||
{
|
||||
return brokerUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBrokerTLSUrl()
|
||||
{
|
||||
return brokerTLSUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHistoricalUrl()
|
||||
{
|
||||
return historicalUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHistoricalTLSUrl()
|
||||
{
|
||||
return historicalTLSUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMiddleManagerHost()
|
||||
{
|
||||
|
|
|
@ -48,30 +48,84 @@ public class DockerConfigProvider implements IntegrationTestingConfigProvider
|
|||
return "http://" + dockerIp + ":8081";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCoordinatorTLSUrl()
|
||||
{
|
||||
return "https://" + dockerIp + ":8281";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIndexerUrl()
|
||||
{
|
||||
return "http://" + dockerIp + ":8090";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIndexerTLSUrl()
|
||||
{
|
||||
return "https://" + dockerIp + ":8290";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRouterUrl()
|
||||
{
|
||||
return "http://" + dockerIp + ":8888";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRouterTLSUrl()
|
||||
{
|
||||
return "https://" + dockerIp + ":9088";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPermissiveRouterUrl()
|
||||
{
|
||||
return "http://" + dockerIp + ":8889";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPermissiveRouterTLSUrl()
|
||||
{
|
||||
return "https://" + dockerIp + ":9089";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNoClientAuthRouterUrl()
|
||||
{
|
||||
return "http://" + dockerIp + ":8890";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNoClientAuthRouterTLSUrl()
|
||||
{
|
||||
return "https://" + dockerIp + ":9090";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBrokerUrl()
|
||||
{
|
||||
return "http://" + dockerIp + ":8082";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBrokerTLSUrl()
|
||||
{
|
||||
return "https://" + dockerIp + ":8282";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHistoricalUrl()
|
||||
{
|
||||
return "http://" + dockerIp + ":8083";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHistoricalTLSUrl()
|
||||
{
|
||||
return "https://" + dockerIp + ":8283";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMiddleManagerHost()
|
||||
{
|
||||
|
|
|
@ -27,14 +27,32 @@ public interface IntegrationTestingConfig
|
|||
{
|
||||
String getCoordinatorUrl();
|
||||
|
||||
String getCoordinatorTLSUrl();
|
||||
|
||||
String getIndexerUrl();
|
||||
|
||||
String getIndexerTLSUrl();
|
||||
|
||||
String getRouterUrl();
|
||||
|
||||
String getRouterTLSUrl();
|
||||
|
||||
String getPermissiveRouterUrl();
|
||||
|
||||
String getPermissiveRouterTLSUrl();
|
||||
|
||||
String getNoClientAuthRouterUrl();
|
||||
|
||||
String getNoClientAuthRouterTLSUrl();
|
||||
|
||||
String getBrokerUrl();
|
||||
|
||||
String getBrokerTLSUrl();
|
||||
|
||||
String getHistoricalUrl();
|
||||
|
||||
String getHistoricalTLSUrl();
|
||||
|
||||
String getMiddleManagerHost();
|
||||
|
||||
String getZookeeperHosts();
|
||||
|
|
|
@ -70,6 +70,11 @@ public class CoordinatorResourceTestClient
|
|||
);
|
||||
}
|
||||
|
||||
private String getMetadataSegmentsURL(String dataSource)
|
||||
{
|
||||
return StringUtils.format("%smetadata/datasources/%s/segments", getCoordinatorURL(), dataSource);
|
||||
}
|
||||
|
||||
private String getIntervalsURL(String dataSource)
|
||||
{
|
||||
return StringUtils.format("%sdatasources/%s/intervals", getCoordinatorURL(), dataSource);
|
||||
|
@ -80,6 +85,25 @@ public class CoordinatorResourceTestClient
|
|||
return StringUtils.format("%s%s", getCoordinatorURL(), "loadstatus");
|
||||
}
|
||||
|
||||
// return a list of the segment dates for the specified datasource
|
||||
public List<String> getMetadataSegments(final String dataSource)
|
||||
{
|
||||
ArrayList<String> segments = null;
|
||||
try {
|
||||
StatusResponseHolder response = makeRequest(HttpMethod.GET, getMetadataSegmentsURL(dataSource));
|
||||
|
||||
segments = jsonMapper.readValue(
|
||||
response.getContent(), new TypeReference<ArrayList<String>>()
|
||||
{
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
return segments;
|
||||
}
|
||||
|
||||
// return a list of the segment dates for the specified datasource
|
||||
public List<String> getSegmentIntervals(final String dataSource)
|
||||
{
|
||||
|
|
|
@ -71,7 +71,7 @@ public class EventReceiverFirehoseTestClient
|
|||
private String getURL()
|
||||
{
|
||||
return StringUtils.format(
|
||||
"http://%s/druid/worker/v1/chat/%s/push-events/",
|
||||
"https://%s/druid/worker/v1/chat/%s/push-events/",
|
||||
host,
|
||||
chatID
|
||||
);
|
||||
|
|
|
@ -175,7 +175,7 @@ public class OverlordResourceTestClient
|
|||
|
||||
public void waitUntilTaskCompletes(final String taskID)
|
||||
{
|
||||
waitUntilTaskCompletes(taskID, 60000, 10);
|
||||
waitUntilTaskCompletes(taskID, 10000, 60);
|
||||
}
|
||||
|
||||
public void waitUntilTaskCompletes(final String taskID, final int millisEach, final int numTimes)
|
||||
|
|
|
@ -32,9 +32,9 @@ public class RetryUtil
|
|||
|
||||
private static final Logger LOG = new Logger(RetryUtil.class);
|
||||
|
||||
public static int DEFAULT_RETRY_COUNT = 10;
|
||||
public static int DEFAULT_RETRY_COUNT = 30;
|
||||
|
||||
public static long DEFAULT_RETRY_SLEEP = TimeUnit.SECONDS.toMillis(30);
|
||||
public static long DEFAULT_RETRY_SLEEP = TimeUnit.SECONDS.toMillis(10);
|
||||
|
||||
public static void retryUntilTrue(Callable<Boolean> callable, String task)
|
||||
{
|
||||
|
|
|
@ -42,6 +42,9 @@ public class TestQueryHelper
|
|||
private final QueryResourceTestClient queryClient;
|
||||
private final ObjectMapper jsonMapper;
|
||||
private final String broker;
|
||||
private final String brokerTLS;
|
||||
private final String router;
|
||||
private final String routerTLS;
|
||||
|
||||
@Inject
|
||||
TestQueryHelper(
|
||||
|
@ -53,11 +56,17 @@ public class TestQueryHelper
|
|||
this.jsonMapper = jsonMapper;
|
||||
this.queryClient = queryClient;
|
||||
this.broker = config.getBrokerUrl();
|
||||
this.brokerTLS = config.getBrokerTLSUrl();
|
||||
this.router = config.getRouterUrl();
|
||||
this.routerTLS = config.getRouterTLSUrl();
|
||||
}
|
||||
|
||||
public void testQueriesFromFile(String filePath, int timesToRun) throws Exception
|
||||
{
|
||||
testQueriesFromFile(getBrokerURL(), filePath, timesToRun);
|
||||
testQueriesFromFile(getQueryURL(broker), filePath, timesToRun);
|
||||
testQueriesFromFile(getQueryURL(brokerTLS), filePath, timesToRun);
|
||||
testQueriesFromFile(getQueryURL(router), filePath, timesToRun);
|
||||
testQueriesFromFile(getQueryURL(routerTLS), filePath, timesToRun);
|
||||
}
|
||||
|
||||
public void testQueriesFromFile(String url, String filePath, int timesToRun) throws Exception
|
||||
|
@ -75,7 +84,10 @@ public class TestQueryHelper
|
|||
|
||||
public void testQueriesFromString(String str, int timesToRun) throws Exception
|
||||
{
|
||||
testQueriesFromString(getBrokerURL(), str, timesToRun);
|
||||
testQueriesFromString(getQueryURL(broker), str, timesToRun);
|
||||
testQueriesFromString(getQueryURL(brokerTLS), str, timesToRun);
|
||||
testQueriesFromString(getQueryURL(router), str, timesToRun);
|
||||
testQueriesFromString(getQueryURL(routerTLS), str, timesToRun);
|
||||
}
|
||||
|
||||
public void testQueriesFromString(String url, String str, int timesToRun) throws Exception
|
||||
|
@ -93,6 +105,7 @@ public class TestQueryHelper
|
|||
|
||||
private void testQueries(String url, List<QueryWithResults> queries, int timesToRun) throws Exception
|
||||
{
|
||||
LOG.info("Running queries, url [%s]", url);
|
||||
for (int i = 0; i < timesToRun; i++) {
|
||||
LOG.info("Starting Iteration %d", i);
|
||||
|
||||
|
@ -119,9 +132,9 @@ public class TestQueryHelper
|
|||
}
|
||||
}
|
||||
|
||||
private String getBrokerURL()
|
||||
private String getQueryURL(String schemeAndHost)
|
||||
{
|
||||
return StringUtils.format("%s/druid/v2?pretty", broker);
|
||||
return StringUtils.format("%s/druid/v2?pretty", schemeAndHost);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -138,7 +151,7 @@ public class TestQueryHelper
|
|||
.intervals(interval)
|
||||
.build();
|
||||
|
||||
List<Map<String, Object>> results = queryClient.query(getBrokerURL(), query);
|
||||
List<Map<String, Object>> results = queryClient.query(getQueryURL(broker), query);
|
||||
if (results.isEmpty()) {
|
||||
return 0;
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,482 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF 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 io.druid.tests.security;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.inject.Inject;
|
||||
import org.apache.druid.guice.annotations.Client;
|
||||
import org.apache.druid.guice.http.DruidHttpClientConfig;
|
||||
import org.apache.druid.guice.http.LifecycleUtils;
|
||||
import org.apache.druid.https.SSLClientConfig;
|
||||
import org.apache.druid.java.util.common.ISE;
|
||||
import org.apache.druid.java.util.common.StringUtils;
|
||||
import org.apache.druid.java.util.common.lifecycle.Lifecycle;
|
||||
import org.apache.druid.java.util.common.logger.Logger;
|
||||
import org.apache.druid.java.util.http.client.CredentialedHttpClient;
|
||||
import org.apache.druid.java.util.http.client.HttpClient;
|
||||
import org.apache.druid.java.util.http.client.HttpClientConfig;
|
||||
import org.apache.druid.java.util.http.client.HttpClientInit;
|
||||
import org.apache.druid.java.util.http.client.Request;
|
||||
import org.apache.druid.java.util.http.client.auth.BasicCredentials;
|
||||
import org.apache.druid.java.util.http.client.response.StatusResponseHandler;
|
||||
import org.apache.druid.java.util.http.client.response.StatusResponseHolder;
|
||||
import org.apache.druid.server.security.TLSUtils;
|
||||
import org.apache.druid.testing.IntegrationTestingConfig;
|
||||
import org.apache.druid.testing.guice.DruidTestModuleFactory;
|
||||
import org.jboss.netty.handler.codec.http.HttpMethod;
|
||||
import org.jboss.netty.handler.codec.http.HttpResponseStatus;
|
||||
import org.joda.time.Duration;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Guice;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@Guice(moduleFactory = DruidTestModuleFactory.class)
|
||||
public class ITTLSTest
|
||||
{
|
||||
private static final Logger LOG = new Logger(ITTLSTest.class);
|
||||
|
||||
private static final Duration SSL_HANDSHAKE_TIMEOUT = new Duration(30 * 1000);
|
||||
|
||||
private static final int MAX_BROKEN_PIPE_RETRIES = 30;
|
||||
|
||||
@Inject
|
||||
IntegrationTestingConfig config;
|
||||
|
||||
@Inject
|
||||
ObjectMapper jsonMapper;
|
||||
|
||||
@Inject
|
||||
SSLClientConfig sslClientConfig;
|
||||
|
||||
@Inject
|
||||
@Client
|
||||
HttpClient httpClient;
|
||||
|
||||
@Inject
|
||||
@Client
|
||||
DruidHttpClientConfig httpClientConfig;
|
||||
|
||||
StatusResponseHandler responseHandler = new StatusResponseHandler(StandardCharsets.UTF_8);
|
||||
|
||||
@Test
|
||||
public void testPlaintextAccess()
|
||||
{
|
||||
LOG.info("---------Testing resource access without TLS---------");
|
||||
HttpClient adminClient = new CredentialedHttpClient(
|
||||
new BasicCredentials("admin", "priest"),
|
||||
httpClient
|
||||
);
|
||||
makeRequest(adminClient, HttpMethod.GET, config.getCoordinatorUrl() + "/status", null);
|
||||
makeRequest(adminClient, HttpMethod.GET, config.getIndexerUrl() + "/status", null);
|
||||
makeRequest(adminClient, HttpMethod.GET, config.getBrokerUrl() + "/status", null);
|
||||
makeRequest(adminClient, HttpMethod.GET, config.getHistoricalUrl() + "/status", null);
|
||||
makeRequest(adminClient, HttpMethod.GET, config.getRouterUrl() + "/status", null);
|
||||
makeRequest(adminClient, HttpMethod.GET, config.getPermissiveRouterUrl() + "/status", null);
|
||||
makeRequest(adminClient, HttpMethod.GET, config.getNoClientAuthRouterUrl() + "/status", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTLSNodeAccess()
|
||||
{
|
||||
LOG.info("---------Testing resource access with TLS enabled---------");
|
||||
HttpClient adminClient = new CredentialedHttpClient(
|
||||
new BasicCredentials("admin", "priest"),
|
||||
httpClient
|
||||
);
|
||||
makeRequest(adminClient, HttpMethod.GET, config.getCoordinatorTLSUrl() + "/status", null);
|
||||
makeRequest(adminClient, HttpMethod.GET, config.getIndexerTLSUrl() + "/status", null);
|
||||
makeRequest(adminClient, HttpMethod.GET, config.getBrokerTLSUrl() + "/status", null);
|
||||
makeRequest(adminClient, HttpMethod.GET, config.getHistoricalTLSUrl() + "/status", null);
|
||||
makeRequest(adminClient, HttpMethod.GET, config.getRouterTLSUrl() + "/status", null);
|
||||
makeRequest(adminClient, HttpMethod.GET, config.getPermissiveRouterTLSUrl() + "/status", null);
|
||||
makeRequest(adminClient, HttpMethod.GET, config.getNoClientAuthRouterTLSUrl() + "/status", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTLSNodeAccessWithIntermediate()
|
||||
{
|
||||
LOG.info("---------Testing TLS resource access with 3-part cert chain---------");
|
||||
HttpClient intermediateCertClient = makeCustomHttpClient(
|
||||
"client_tls/intermediate_ca_client.jks",
|
||||
"intermediate_ca_client"
|
||||
);
|
||||
makeRequest(intermediateCertClient, HttpMethod.GET, config.getCoordinatorTLSUrl() + "/status", null);
|
||||
makeRequest(intermediateCertClient, HttpMethod.GET, config.getIndexerTLSUrl() + "/status", null);
|
||||
makeRequest(intermediateCertClient, HttpMethod.GET, config.getBrokerTLSUrl() + "/status", null);
|
||||
makeRequest(intermediateCertClient, HttpMethod.GET, config.getHistoricalTLSUrl() + "/status", null);
|
||||
makeRequest(intermediateCertClient, HttpMethod.GET, config.getRouterTLSUrl() + "/status", null);
|
||||
makeRequest(intermediateCertClient, HttpMethod.GET, config.getPermissiveRouterTLSUrl() + "/status", null);
|
||||
makeRequest(intermediateCertClient, HttpMethod.GET, config.getNoClientAuthRouterTLSUrl() + "/status", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkAccessWithNoCert()
|
||||
{
|
||||
LOG.info("---------Testing TLS resource access without a certificate---------");
|
||||
HttpClient certlessClient = makeCertlessClient();
|
||||
checkFailedAccessNoCert(certlessClient, HttpMethod.GET, config.getCoordinatorTLSUrl());
|
||||
checkFailedAccessNoCert(certlessClient, HttpMethod.GET, config.getIndexerTLSUrl());
|
||||
checkFailedAccessNoCert(certlessClient, HttpMethod.GET, config.getBrokerTLSUrl());
|
||||
checkFailedAccessNoCert(certlessClient, HttpMethod.GET, config.getHistoricalTLSUrl());
|
||||
checkFailedAccessNoCert(certlessClient, HttpMethod.GET, config.getRouterTLSUrl());
|
||||
checkFailedAccessNoCert(certlessClient, HttpMethod.GET, config.getPermissiveRouterTLSUrl());
|
||||
makeRequest(certlessClient, HttpMethod.GET, config.getNoClientAuthRouterTLSUrl() + "/status", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkAccessWithWrongHostname()
|
||||
{
|
||||
LOG.info("---------Testing TLS resource access when client certificate has non-matching hostnames---------");
|
||||
HttpClient wrongHostnameClient = makeCustomHttpClient(
|
||||
"client_tls/invalid_hostname_client.jks",
|
||||
"invalid_hostname_client"
|
||||
);
|
||||
checkFailedAccessWrongHostname(wrongHostnameClient, HttpMethod.GET, config.getCoordinatorTLSUrl());
|
||||
checkFailedAccessWrongHostname(wrongHostnameClient, HttpMethod.GET, config.getIndexerTLSUrl());
|
||||
checkFailedAccessWrongHostname(wrongHostnameClient, HttpMethod.GET, config.getBrokerTLSUrl());
|
||||
checkFailedAccessWrongHostname(wrongHostnameClient, HttpMethod.GET, config.getHistoricalTLSUrl());
|
||||
checkFailedAccessWrongHostname(wrongHostnameClient, HttpMethod.GET, config.getRouterTLSUrl());
|
||||
makeRequest(wrongHostnameClient, HttpMethod.GET, config.getPermissiveRouterTLSUrl() + "/status", null);
|
||||
makeRequest(wrongHostnameClient, HttpMethod.GET, config.getNoClientAuthRouterTLSUrl() + "/status", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkAccessWithWrongRoot()
|
||||
{
|
||||
LOG.info("---------Testing TLS resource access when client certificate is signed by a non-trusted root CA---------");
|
||||
HttpClient wrongRootClient = makeCustomHttpClient(
|
||||
"client_tls/client_another_root.jks",
|
||||
"druid_another_root"
|
||||
);
|
||||
checkFailedAccessWrongRoot(wrongRootClient, HttpMethod.GET, config.getCoordinatorTLSUrl());
|
||||
checkFailedAccessWrongRoot(wrongRootClient, HttpMethod.GET, config.getIndexerTLSUrl());
|
||||
checkFailedAccessWrongRoot(wrongRootClient, HttpMethod.GET, config.getBrokerTLSUrl());
|
||||
checkFailedAccessWrongRoot(wrongRootClient, HttpMethod.GET, config.getHistoricalTLSUrl());
|
||||
checkFailedAccessWrongRoot(wrongRootClient, HttpMethod.GET, config.getRouterTLSUrl());
|
||||
checkFailedAccessWrongRoot(wrongRootClient, HttpMethod.GET, config.getPermissiveRouterTLSUrl());
|
||||
makeRequest(wrongRootClient, HttpMethod.GET, config.getNoClientAuthRouterTLSUrl() + "/status", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkAccessWithRevokedCert()
|
||||
{
|
||||
LOG.info("---------Testing TLS resource access when client certificate has been revoked---------");
|
||||
HttpClient revokedClient = makeCustomHttpClient(
|
||||
"client_tls/revoked_client.jks",
|
||||
"revoked_druid"
|
||||
);
|
||||
checkFailedAccessRevoked(revokedClient, HttpMethod.GET, config.getCoordinatorTLSUrl());
|
||||
checkFailedAccessRevoked(revokedClient, HttpMethod.GET, config.getIndexerTLSUrl());
|
||||
checkFailedAccessRevoked(revokedClient, HttpMethod.GET, config.getBrokerTLSUrl());
|
||||
checkFailedAccessRevoked(revokedClient, HttpMethod.GET, config.getHistoricalTLSUrl());
|
||||
checkFailedAccessRevoked(revokedClient, HttpMethod.GET, config.getRouterTLSUrl());
|
||||
makeRequest(revokedClient, HttpMethod.GET, config.getPermissiveRouterTLSUrl() + "/status", null);
|
||||
makeRequest(revokedClient, HttpMethod.GET, config.getNoClientAuthRouterTLSUrl() + "/status", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkAccessWithExpiredCert()
|
||||
{
|
||||
LOG.info("---------Testing TLS resource access when client certificate has expired---------");
|
||||
HttpClient expiredClient = makeCustomHttpClient(
|
||||
"client_tls/expired_client.jks",
|
||||
"expired_client"
|
||||
);
|
||||
checkFailedAccessExpired(expiredClient, HttpMethod.GET, config.getCoordinatorTLSUrl());
|
||||
checkFailedAccessExpired(expiredClient, HttpMethod.GET, config.getIndexerTLSUrl());
|
||||
checkFailedAccessExpired(expiredClient, HttpMethod.GET, config.getBrokerTLSUrl());
|
||||
checkFailedAccessExpired(expiredClient, HttpMethod.GET, config.getHistoricalTLSUrl());
|
||||
checkFailedAccessExpired(expiredClient, HttpMethod.GET, config.getRouterTLSUrl());
|
||||
checkFailedAccessExpired(expiredClient, HttpMethod.GET, config.getPermissiveRouterTLSUrl());
|
||||
makeRequest(expiredClient, HttpMethod.GET, config.getNoClientAuthRouterTLSUrl() + "/status", null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkAccessWithNotCASignedCert()
|
||||
{
|
||||
LOG.info(
|
||||
"---------Testing TLS resource access when client certificate is signed by a non-CA intermediate cert---------");
|
||||
HttpClient notCAClient = makeCustomHttpClient(
|
||||
"client_tls/invalid_ca_client.jks",
|
||||
"invalid_ca_client"
|
||||
);
|
||||
checkFailedAccessNotCA(notCAClient, HttpMethod.GET, config.getCoordinatorTLSUrl());
|
||||
checkFailedAccessNotCA(notCAClient, HttpMethod.GET, config.getIndexerTLSUrl());
|
||||
checkFailedAccessNotCA(notCAClient, HttpMethod.GET, config.getBrokerTLSUrl());
|
||||
checkFailedAccessNotCA(notCAClient, HttpMethod.GET, config.getHistoricalTLSUrl());
|
||||
checkFailedAccessNotCA(notCAClient, HttpMethod.GET, config.getRouterTLSUrl());
|
||||
checkFailedAccessNotCA(notCAClient, HttpMethod.GET, config.getPermissiveRouterTLSUrl());
|
||||
makeRequest(notCAClient, HttpMethod.GET, config.getNoClientAuthRouterTLSUrl() + "/status", null);
|
||||
}
|
||||
|
||||
private void checkFailedAccessNoCert(HttpClient httpClient, HttpMethod method, String url)
|
||||
{
|
||||
checkFailedAccess(
|
||||
httpClient,
|
||||
method,
|
||||
url + "/status",
|
||||
"Certless",
|
||||
SSLException.class,
|
||||
"Received fatal alert: bad_certificate"
|
||||
);
|
||||
}
|
||||
|
||||
private void checkFailedAccessWrongHostname(HttpClient httpClient, HttpMethod method, String url)
|
||||
{
|
||||
checkFailedAccess(
|
||||
httpClient,
|
||||
method,
|
||||
url + "/status",
|
||||
"Wrong hostname",
|
||||
SSLException.class,
|
||||
"Received fatal alert: certificate_unknown"
|
||||
);
|
||||
}
|
||||
|
||||
private void checkFailedAccessWrongRoot(HttpClient httpClient, HttpMethod method, String url)
|
||||
{
|
||||
checkFailedAccess(
|
||||
httpClient,
|
||||
method,
|
||||
url + "/status",
|
||||
"Wrong root cert",
|
||||
SSLException.class,
|
||||
"Received fatal alert: certificate_unknown"
|
||||
);
|
||||
}
|
||||
|
||||
private void checkFailedAccessRevoked(HttpClient httpClient, HttpMethod method, String url)
|
||||
{
|
||||
checkFailedAccess(
|
||||
httpClient,
|
||||
method,
|
||||
url + "/status",
|
||||
"Revoked cert",
|
||||
SSLException.class,
|
||||
"Received fatal alert: certificate_unknown"
|
||||
);
|
||||
}
|
||||
|
||||
private void checkFailedAccessExpired(HttpClient httpClient, HttpMethod method, String url)
|
||||
{
|
||||
checkFailedAccess(
|
||||
httpClient,
|
||||
method,
|
||||
url + "/status",
|
||||
"Expired cert",
|
||||
SSLException.class,
|
||||
"Received fatal alert: certificate_unknown"
|
||||
);
|
||||
}
|
||||
|
||||
private void checkFailedAccessNotCA(HttpClient httpClient, HttpMethod method, String url)
|
||||
{
|
||||
checkFailedAccess(
|
||||
httpClient,
|
||||
method,
|
||||
url + "/status",
|
||||
"Cert signed by non-CA",
|
||||
SSLException.class,
|
||||
"Received fatal alert: certificate_unknown"
|
||||
);
|
||||
}
|
||||
|
||||
private HttpClientConfig.Builder getHttpClientConfigBuilder(SSLContext sslContext)
|
||||
{
|
||||
return HttpClientConfig
|
||||
.builder()
|
||||
.withNumConnections(httpClientConfig.getNumConnections())
|
||||
.withReadTimeout(httpClientConfig.getReadTimeout())
|
||||
.withWorkerCount(httpClientConfig.getNumMaxThreads())
|
||||
.withCompressionCodec(
|
||||
HttpClientConfig.CompressionCodec.valueOf(StringUtils.toUpperCase(httpClientConfig.getCompressionCodec()))
|
||||
)
|
||||
.withUnusedConnectionTimeoutDuration(httpClientConfig.getUnusedConnectionTimeout())
|
||||
.withSslHandshakeTimeout(SSL_HANDSHAKE_TIMEOUT)
|
||||
.withSslContext(sslContext);
|
||||
}
|
||||
|
||||
private HttpClient makeCustomHttpClient(String keystorePath, String certAlias)
|
||||
{
|
||||
SSLContext intermediateClientSSLContext = new TLSUtils.ClientSSLContextBuilder()
|
||||
.setProtocol(sslClientConfig.getProtocol())
|
||||
.setTrustStoreType(sslClientConfig.getTrustStoreType())
|
||||
.setTrustStorePath(sslClientConfig.getTrustStorePath())
|
||||
.setTrustStoreAlgorithm(sslClientConfig.getTrustStoreAlgorithm())
|
||||
.setTrustStorePasswordProvider(sslClientConfig.getTrustStorePasswordProvider())
|
||||
.setKeyStoreType(sslClientConfig.getKeyStoreType())
|
||||
.setKeyStorePath(keystorePath)
|
||||
.setKeyStoreAlgorithm(sslClientConfig.getKeyManagerFactoryAlgorithm())
|
||||
.setCertAlias(certAlias)
|
||||
.setKeyStorePasswordProvider(sslClientConfig.getKeyStorePasswordProvider())
|
||||
.setKeyManagerFactoryPasswordProvider(sslClientConfig.getKeyManagerPasswordProvider())
|
||||
.build();
|
||||
|
||||
final HttpClientConfig.Builder builder = getHttpClientConfigBuilder(intermediateClientSSLContext);
|
||||
|
||||
final Lifecycle lifecycle = new Lifecycle();
|
||||
|
||||
HttpClient client = HttpClientInit.createClient(
|
||||
builder.build(),
|
||||
LifecycleUtils.asMmxLifecycle(lifecycle)
|
||||
);
|
||||
|
||||
HttpClient adminClient = new CredentialedHttpClient(
|
||||
new BasicCredentials("admin", "priest"),
|
||||
client
|
||||
);
|
||||
return adminClient;
|
||||
}
|
||||
|
||||
private HttpClient makeCertlessClient()
|
||||
{
|
||||
SSLContext certlessClientSSLContext = new TLSUtils.ClientSSLContextBuilder()
|
||||
.setProtocol(sslClientConfig.getProtocol())
|
||||
.setTrustStoreType(sslClientConfig.getTrustStoreType())
|
||||
.setTrustStorePath(sslClientConfig.getTrustStorePath())
|
||||
.setTrustStoreAlgorithm(sslClientConfig.getTrustStoreAlgorithm())
|
||||
.setTrustStorePasswordProvider(sslClientConfig.getTrustStorePasswordProvider())
|
||||
.build();
|
||||
|
||||
final HttpClientConfig.Builder builder = getHttpClientConfigBuilder(certlessClientSSLContext);
|
||||
|
||||
final Lifecycle lifecycle = new Lifecycle();
|
||||
|
||||
HttpClient client = HttpClientInit.createClient(
|
||||
builder.build(),
|
||||
LifecycleUtils.asMmxLifecycle(lifecycle)
|
||||
);
|
||||
|
||||
HttpClient adminClient = new CredentialedHttpClient(
|
||||
new BasicCredentials("admin", "priest"),
|
||||
client
|
||||
);
|
||||
return adminClient;
|
||||
}
|
||||
|
||||
private void checkFailedAccess(
|
||||
HttpClient httpClient,
|
||||
HttpMethod method,
|
||||
String url,
|
||||
String clientDesc,
|
||||
Class expectedException,
|
||||
String expectedExceptionMsg
|
||||
)
|
||||
{
|
||||
int retries = 0;
|
||||
while (true) {
|
||||
try {
|
||||
makeRequest(httpClient, method, url, null, -1);
|
||||
}
|
||||
catch (RuntimeException re) {
|
||||
Throwable rootCause = Throwables.getRootCause(re);
|
||||
|
||||
if (rootCause instanceof IOException && "Broken pipe".equals(rootCause.getMessage())) {
|
||||
if (retries > MAX_BROKEN_PIPE_RETRIES) {
|
||||
Assert.fail(StringUtils.format(
|
||||
"Broken pipe retries exhausted, test failed, did not get %s.",
|
||||
expectedException
|
||||
));
|
||||
} else {
|
||||
retries += 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Assert.assertTrue(
|
||||
expectedException.isInstance(rootCause),
|
||||
StringUtils.format("Expected %s but found %s instead.", expectedException, rootCause)
|
||||
);
|
||||
|
||||
Assert.assertEquals(
|
||||
rootCause.getMessage(),
|
||||
expectedExceptionMsg
|
||||
);
|
||||
|
||||
LOG.info("%s client [%s] request failed as expected when accessing [%s]", clientDesc, method, url);
|
||||
return;
|
||||
}
|
||||
Assert.fail(StringUtils.format("Test failed, did not get %s.", expectedException));
|
||||
}
|
||||
}
|
||||
|
||||
private StatusResponseHolder makeRequest(HttpClient httpClient, HttpMethod method, String url, byte[] content)
|
||||
{
|
||||
return makeRequest(httpClient, method, url, content, 4);
|
||||
}
|
||||
|
||||
private StatusResponseHolder makeRequest(
|
||||
HttpClient httpClient,
|
||||
HttpMethod method,
|
||||
String url,
|
||||
byte[] content,
|
||||
int maxRetries
|
||||
)
|
||||
{
|
||||
try {
|
||||
Request request = new Request(method, new URL(url));
|
||||
if (content != null) {
|
||||
request.setContent(MediaType.APPLICATION_JSON, content);
|
||||
}
|
||||
int retryCount = 0;
|
||||
|
||||
StatusResponseHolder response;
|
||||
|
||||
while (true) {
|
||||
response = httpClient.go(
|
||||
request,
|
||||
responseHandler
|
||||
).get();
|
||||
|
||||
if (!response.getStatus().equals(HttpResponseStatus.OK)) {
|
||||
String errMsg = StringUtils.format(
|
||||
"Error while making request to url[%s] status[%s] content[%s]",
|
||||
url,
|
||||
response.getStatus(),
|
||||
response.getContent()
|
||||
);
|
||||
if (retryCount > maxRetries) {
|
||||
throw new ISE(errMsg);
|
||||
} else {
|
||||
LOG.error(errMsg);
|
||||
LOG.error("retrying in 3000ms, retryCount: " + retryCount);
|
||||
retryCount++;
|
||||
Thread.sleep(3000);
|
||||
}
|
||||
} else {
|
||||
LOG.info("[%s] request to [%s] succeeded.", method, url);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -75,7 +75,7 @@ public class ITHadoopIndexTest extends AbstractIndexerTest
|
|||
try {
|
||||
final String taskID = indexer.submitTask(indexerSpec);
|
||||
LOG.info("TaskID for loading index task %s", taskID);
|
||||
indexer.waitUntilTaskCompletes(taskID, 60000, 20);
|
||||
indexer.waitUntilTaskCompletes(taskID, 10000, 120);
|
||||
RetryUtil.retryUntil(
|
||||
new Callable<Boolean>()
|
||||
{
|
||||
|
|
|
@ -142,8 +142,8 @@ public abstract class AbstractITRealtimeIndexTaskTest extends AbstractIndexerTes
|
|||
}
|
||||
},
|
||||
true,
|
||||
60000,
|
||||
10,
|
||||
10000,
|
||||
60,
|
||||
"Real-time generated segments loaded"
|
||||
);
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ public class ITCompactionTaskTest extends AbstractIndexerTest
|
|||
{
|
||||
loadData();
|
||||
final List<String> intervalsBeforeCompaction = coordinator.getSegmentIntervals(INDEX_DATASOURCE);
|
||||
intervalsBeforeCompaction.sort(null);
|
||||
final String compactedInterval = "2013-08-31T00:00:00.000Z/2013-09-02T00:00:00.000Z";
|
||||
if (intervalsBeforeCompaction.contains(compactedInterval)) {
|
||||
throw new ISE("Containing a segment for the compacted interval[%s] before compaction", compactedInterval);
|
||||
|
@ -49,12 +50,14 @@ public class ITCompactionTaskTest extends AbstractIndexerTest
|
|||
try {
|
||||
queryHelper.testQueriesFromFile(INDEX_QUERIES_RESOURCE, 2);
|
||||
compactData(false);
|
||||
|
||||
// 4 segments across 2 days, compacted into 1 new segment (5 total)
|
||||
checkCompactionFinished(5);
|
||||
queryHelper.testQueriesFromFile(INDEX_QUERIES_RESOURCE, 2);
|
||||
|
||||
final List<String> intervalsAfterCompaction = coordinator.getSegmentIntervals(INDEX_DATASOURCE);
|
||||
if (!intervalsAfterCompaction.contains(compactedInterval)) {
|
||||
throw new ISE("Compacted segment for interval[%s] does not exist", compactedInterval);
|
||||
}
|
||||
intervalsBeforeCompaction.add(compactedInterval);
|
||||
intervalsBeforeCompaction.sort(null);
|
||||
checkCompactionIntervals(intervalsBeforeCompaction);
|
||||
}
|
||||
finally {
|
||||
unloadAndKillData(INDEX_DATASOURCE);
|
||||
|
@ -66,21 +69,16 @@ public class ITCompactionTaskTest extends AbstractIndexerTest
|
|||
{
|
||||
loadData();
|
||||
final List<String> intervalsBeforeCompaction = coordinator.getSegmentIntervals(INDEX_DATASOURCE);
|
||||
intervalsBeforeCompaction.sort(null);
|
||||
try {
|
||||
queryHelper.testQueriesFromFile(INDEX_QUERIES_RESOURCE, 2);
|
||||
compactData(true);
|
||||
|
||||
// 4 segments across 2 days, compacted into 2 new segments (6 total)
|
||||
checkCompactionFinished(6);
|
||||
queryHelper.testQueriesFromFile(INDEX_QUERIES_RESOURCE, 2);
|
||||
|
||||
final List<String> intervalsAfterCompaction = coordinator.getSegmentIntervals(INDEX_DATASOURCE);
|
||||
intervalsBeforeCompaction.sort(null);
|
||||
intervalsAfterCompaction.sort(null);
|
||||
if (!intervalsBeforeCompaction.equals(intervalsAfterCompaction)) {
|
||||
throw new ISE(
|
||||
"Intervals before compaction[%s] should be same with those after compaction[%s]",
|
||||
intervalsBeforeCompaction,
|
||||
intervalsAfterCompaction
|
||||
);
|
||||
}
|
||||
checkCompactionIntervals(intervalsBeforeCompaction);
|
||||
}
|
||||
finally {
|
||||
unloadAndKillData(INDEX_DATASOURCE);
|
||||
|
@ -112,4 +110,30 @@ public class ITCompactionTaskTest extends AbstractIndexerTest
|
|||
"Segment Compaction"
|
||||
);
|
||||
}
|
||||
|
||||
private void checkCompactionFinished(int numExpectedSegments)
|
||||
{
|
||||
RetryUtil.retryUntilTrue(
|
||||
() -> {
|
||||
int metadataSegmentCount = coordinator.getMetadataSegments(INDEX_DATASOURCE).size();
|
||||
LOG.info("Current metadata segment count: %d, expected: %d", metadataSegmentCount, numExpectedSegments);
|
||||
return metadataSegmentCount == numExpectedSegments;
|
||||
},
|
||||
"Compaction segment count check"
|
||||
);
|
||||
}
|
||||
|
||||
private void checkCompactionIntervals(List<String> expectedIntervals)
|
||||
{
|
||||
RetryUtil.retryUntilTrue(
|
||||
() -> {
|
||||
final List<String> intervalsAfterCompaction = coordinator.getSegmentIntervals(INDEX_DATASOURCE);
|
||||
intervalsAfterCompaction.sort(null);
|
||||
System.out.println("AFTER: " + intervalsAfterCompaction);
|
||||
System.out.println("EXPECTED: " + expectedIntervals);
|
||||
return intervalsAfterCompaction.equals(expectedIntervals);
|
||||
},
|
||||
"Compaction interval check"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -278,8 +278,8 @@ public class ITKafkaIndexingServiceTest extends AbstractIndexerTest
|
|||
}
|
||||
},
|
||||
true,
|
||||
30000,
|
||||
10,
|
||||
10000,
|
||||
30,
|
||||
"Real-time generated segments loaded"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -226,7 +226,7 @@ public class ITKafkaTest extends AbstractIndexerTest
|
|||
LOG.info("-------------SUBMITTED TASK");
|
||||
|
||||
// wait for the task to finish
|
||||
indexer.waitUntilTaskCompletes(taskID, 20000, 30);
|
||||
indexer.waitUntilTaskCompletes(taskID, 10000, 60);
|
||||
|
||||
// wait for segments to be handed off
|
||||
try {
|
||||
|
@ -240,8 +240,8 @@ public class ITKafkaTest extends AbstractIndexerTest
|
|||
}
|
||||
},
|
||||
true,
|
||||
30000,
|
||||
10,
|
||||
10000,
|
||||
30,
|
||||
"Real-time generated segments loaded"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -25,18 +25,26 @@ import com.google.inject.Inject;
|
|||
import org.apache.druid.curator.discovery.ServerDiscoveryFactory;
|
||||
import org.apache.druid.curator.discovery.ServerDiscoverySelector;
|
||||
import org.apache.druid.java.util.common.DateTimes;
|
||||
import org.apache.druid.java.util.common.StringUtils;
|
||||
import org.apache.druid.java.util.common.logger.Logger;
|
||||
import org.apache.druid.java.util.http.client.HttpClient;
|
||||
import org.apache.druid.java.util.http.client.Request;
|
||||
import org.apache.druid.java.util.http.client.response.StatusResponseHandler;
|
||||
import org.apache.druid.java.util.http.client.response.StatusResponseHolder;
|
||||
import org.apache.druid.testing.IntegrationTestingConfig;
|
||||
import org.apache.druid.testing.clients.EventReceiverFirehoseTestClient;
|
||||
import org.apache.druid.testing.guice.DruidTestModuleFactory;
|
||||
import org.apache.druid.testing.guice.TestClient;
|
||||
import org.apache.druid.testing.utils.RetryUtil;
|
||||
import org.apache.druid.testing.utils.ServerDiscoveryUtil;
|
||||
import org.jboss.netty.handler.codec.http.HttpMethod;
|
||||
import org.jboss.netty.handler.codec.http.HttpResponseStatus;
|
||||
import org.joda.time.DateTime;
|
||||
import org.testng.annotations.Guice;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -173,6 +181,26 @@ public class ITUnionQueryTest extends AbstractIndexerTest
|
|||
|
||||
LOG.info("Event Receiver Found at host [%s]", host);
|
||||
|
||||
LOG.info("Checking worker /status/health for [%s]", host);
|
||||
final StatusResponseHandler handler = new StatusResponseHandler(StandardCharsets.UTF_8);
|
||||
RetryUtil.retryUntilTrue(
|
||||
() -> {
|
||||
try {
|
||||
StatusResponseHolder response = httpClient.go(
|
||||
new Request(HttpMethod.GET, new URL(StringUtils.format("https://%s/status/health", host))),
|
||||
handler
|
||||
).get();
|
||||
return response.getStatus().equals(HttpResponseStatus.OK);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.error(e, "");
|
||||
return false;
|
||||
}
|
||||
},
|
||||
StringUtils.format("Checking /status/health for worker [%s]", host)
|
||||
);
|
||||
LOG.info("Finished checking worker /status/health for [%s], success", host);
|
||||
|
||||
EventReceiverFirehoseTestClient client = new EventReceiverFirehoseTestClient(
|
||||
host,
|
||||
EVENT_RECEIVER_SERVICE_PREFIX + id,
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
"type" : "realtime",
|
||||
"maxRowsInMemory": 500000,
|
||||
"intermediatePersistPeriod": "PT3M",
|
||||
"windowPeriod": "PT1M",
|
||||
"windowPeriod": "PT150S",
|
||||
"basePersistDirectory": "/home/y/var/druid_state/kafka_test/realtime/basePersist"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,8 +14,11 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
for node in druid-historical druid-coordinator druid-overlord druid-router druid-broker druid-middlemanager druid-zookeeper-kafka druid-metadata-storage;
|
||||
do
|
||||
for node in druid-historical druid-coordinator druid-overlord druid-router druid-router-permissive-tls druid-router-no-client-auth-tls druid-broker druid-middlemanager druid-zookeeper-kafka druid-metadata-storage;
|
||||
|
||||
do
|
||||
docker stop $node
|
||||
docker rm $node
|
||||
done
|
||||
|
||||
docker network rm druid-it-net
|
||||
|
|
1
pom.xml
1
pom.xml
|
@ -1106,6 +1106,7 @@
|
|||
<exclude>**/tutorial/conf/**</exclude>
|
||||
<exclude>**/derby.log</exclude>
|
||||
<exclude>**/docker/**</exclude>
|
||||
<exclude>**/client_tls/**</exclude>
|
||||
<!--IDE MODULE FILES-->
|
||||
<exclude>**/*.iml</exclude>
|
||||
<!--CRASH LOGS-->
|
||||
|
|
|
@ -31,9 +31,11 @@ import org.apache.druid.server.http.security.ConfigResourceFilter;
|
|||
import org.apache.druid.server.http.security.StateResourceFilter;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
@ -47,7 +49,6 @@ import java.util.Set;
|
|||
@Path("/status")
|
||||
public class StatusResource
|
||||
{
|
||||
|
||||
private final Properties properties;
|
||||
|
||||
private final DruidServerConfig druidServerConfig;
|
||||
|
@ -73,7 +74,9 @@ public class StatusResource
|
|||
@GET
|
||||
@ResourceFilters(StateResourceFilter.class)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Status doGet()
|
||||
public Status doGet(
|
||||
@Context final HttpServletRequest req
|
||||
)
|
||||
{
|
||||
return new Status(Initialization.getLoadedImplementations(DruidModule.class));
|
||||
}
|
||||
|
|
|
@ -126,13 +126,13 @@ public class HttpEmitterModule implements Module
|
|||
}
|
||||
} else if (sslConfig.getTrustStorePath() != null) {
|
||||
log.info("Creating SSLContext for HttpEmitter client using config [%s]", sslConfig);
|
||||
effectiveSSLContext = TLSUtils.createSSLContext(
|
||||
sslConfig.getProtocol(),
|
||||
sslConfig.getTrustStoreType(),
|
||||
sslConfig.getTrustStorePath(),
|
||||
sslConfig.getTrustStoreAlgorithm(),
|
||||
sslConfig.getTrustStorePasswordProvider()
|
||||
);
|
||||
effectiveSSLContext = new TLSUtils.ClientSSLContextBuilder()
|
||||
.setProtocol(sslConfig.getProtocol())
|
||||
.setTrustStoreType(sslConfig.getTrustStoreType())
|
||||
.setTrustStorePath(sslConfig.getTrustStorePath())
|
||||
.setTrustStoreAlgorithm(sslConfig.getTrustStoreAlgorithm())
|
||||
.setTrustStorePasswordProvider(sslConfig.getTrustStorePasswordProvider())
|
||||
.build();
|
||||
} else {
|
||||
effectiveSSLContext = sslContext;
|
||||
}
|
||||
|
|
|
@ -23,12 +23,17 @@ import com.google.common.base.Throwables;
|
|||
import com.google.inject.Inject;
|
||||
import org.apache.druid.client.indexing.IndexingService;
|
||||
import org.apache.druid.discovery.DruidLeaderClient;
|
||||
import org.apache.druid.guice.annotations.Global;
|
||||
import org.apache.druid.guice.http.DruidHttpClientConfig;
|
||||
import org.apache.druid.java.util.common.ISE;
|
||||
import org.apache.druid.java.util.common.StringUtils;
|
||||
import org.apache.druid.server.security.AuthConfig;
|
||||
import com.google.inject.Provider;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.proxy.ProxyServlet;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.net.URI;
|
||||
|
@ -40,13 +45,19 @@ import java.net.URISyntaxException;
|
|||
public class OverlordProxyServlet extends ProxyServlet
|
||||
{
|
||||
private final DruidLeaderClient druidLeaderClient;
|
||||
private final Provider<HttpClient> httpClientProvider;
|
||||
private final DruidHttpClientConfig httpClientConfig;
|
||||
|
||||
@Inject
|
||||
OverlordProxyServlet(
|
||||
@IndexingService DruidLeaderClient druidLeaderClient
|
||||
@IndexingService DruidLeaderClient druidLeaderClient,
|
||||
@Global Provider<HttpClient> httpClientProvider,
|
||||
@Global DruidHttpClientConfig httpClientConfig
|
||||
)
|
||||
{
|
||||
this.druidLeaderClient = druidLeaderClient;
|
||||
this.httpClientProvider = httpClientProvider;
|
||||
this.httpClientConfig = httpClientConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -71,6 +82,22 @@ public class OverlordProxyServlet extends ProxyServlet
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpClient newHttpClient()
|
||||
{
|
||||
return httpClientProvider.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpClient createHttpClient() throws ServletException
|
||||
{
|
||||
HttpClient client = super.createHttpClient();
|
||||
// override timeout set in ProxyServlet.createHttpClient
|
||||
setTimeout(httpClientConfig.getReadTimeout().getMillis());
|
||||
return client;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void sendProxyRequest(
|
||||
HttpServletRequest clientRequest,
|
||||
|
|
|
@ -55,6 +55,27 @@ public class TLSServerConfig
|
|||
@JsonProperty
|
||||
private List<String> excludeProtocols;
|
||||
|
||||
@JsonProperty
|
||||
private boolean requireClientCertificate = false;
|
||||
|
||||
@JsonProperty
|
||||
private String trustStoreType;
|
||||
|
||||
@JsonProperty
|
||||
private String trustStorePath;
|
||||
|
||||
@JsonProperty
|
||||
private String trustStoreAlgorithm;
|
||||
|
||||
@JsonProperty("trustStorePassword")
|
||||
private PasswordProvider trustStorePasswordProvider;
|
||||
|
||||
@JsonProperty
|
||||
private boolean validateHostnames = true;
|
||||
|
||||
@JsonProperty
|
||||
private String crlPath;
|
||||
|
||||
public String getKeyStorePath()
|
||||
{
|
||||
return keyStorePath;
|
||||
|
@ -105,6 +126,41 @@ public class TLSServerConfig
|
|||
return excludeProtocols;
|
||||
}
|
||||
|
||||
public boolean isRequireClientCertificate()
|
||||
{
|
||||
return requireClientCertificate;
|
||||
}
|
||||
|
||||
public String getTrustStoreType()
|
||||
{
|
||||
return trustStoreType;
|
||||
}
|
||||
|
||||
public String getTrustStorePath()
|
||||
{
|
||||
return trustStorePath;
|
||||
}
|
||||
|
||||
public String getTrustStoreAlgorithm()
|
||||
{
|
||||
return trustStoreAlgorithm;
|
||||
}
|
||||
|
||||
public PasswordProvider getTrustStorePasswordProvider()
|
||||
{
|
||||
return trustStorePasswordProvider;
|
||||
}
|
||||
|
||||
public boolean isValidateHostnames()
|
||||
{
|
||||
return validateHostnames;
|
||||
}
|
||||
|
||||
public String getCrlPath()
|
||||
{
|
||||
return crlPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
@ -117,6 +173,12 @@ public class TLSServerConfig
|
|||
", excludeCipherSuites=" + excludeCipherSuites +
|
||||
", includeProtocols=" + includeProtocols +
|
||||
", excludeProtocols=" + excludeProtocols +
|
||||
", requireClientCertificate=" + requireClientCertificate +
|
||||
", trustStoreType='" + trustStoreType + '\'' +
|
||||
", trustStorePath='" + trustStorePath + '\'' +
|
||||
", trustStoreAlgorithm='" + trustStoreAlgorithm + '\'' +
|
||||
", validateHostnames='" + validateHostnames + '\'' +
|
||||
", crlPath='" + crlPath + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,6 +75,8 @@ import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
|
|||
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import java.security.KeyStore;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
@ -231,6 +233,7 @@ public class JettyServerModule extends JerseyServletModule
|
|||
if (sslContextFactoryBinding == null) {
|
||||
// Never trust all certificates by default
|
||||
sslContextFactory = new SslContextFactory(false);
|
||||
|
||||
sslContextFactory.setKeyStorePath(tlsServerConfig.getKeyStorePath());
|
||||
sslContextFactory.setKeyStoreType(tlsServerConfig.getKeyStoreType());
|
||||
sslContextFactory.setKeyStorePassword(tlsServerConfig.getKeyStorePasswordProvider().getPassword());
|
||||
|
@ -256,6 +259,37 @@ public class JettyServerModule extends JerseyServletModule
|
|||
sslContextFactory.setExcludeProtocols(
|
||||
tlsServerConfig.getExcludeProtocols().toArray(new String[0]));
|
||||
}
|
||||
|
||||
sslContextFactory.setNeedClientAuth(tlsServerConfig.isRequireClientCertificate());
|
||||
if (tlsServerConfig.isRequireClientCertificate()) {
|
||||
if (tlsServerConfig.getCrlPath() != null) {
|
||||
// setValidatePeerCerts is used just to enable revocation checking using a static CRL file.
|
||||
// Certificate validation is always performed when client certificates are required.
|
||||
sslContextFactory.setValidatePeerCerts(true);
|
||||
sslContextFactory.setCrlPath(tlsServerConfig.getCrlPath());
|
||||
}
|
||||
if (tlsServerConfig.isValidateHostnames()) {
|
||||
sslContextFactory.setEndpointIdentificationAlgorithm("HTTPS");
|
||||
}
|
||||
if (tlsServerConfig.getTrustStorePath() != null) {
|
||||
sslContextFactory.setTrustStorePath(tlsServerConfig.getTrustStorePath());
|
||||
sslContextFactory.setTrustStoreType(
|
||||
tlsServerConfig.getTrustStoreType() == null
|
||||
? KeyStore.getDefaultType()
|
||||
: tlsServerConfig.getTrustStoreType()
|
||||
);
|
||||
sslContextFactory.setTrustManagerFactoryAlgorithm(
|
||||
tlsServerConfig.getTrustStoreAlgorithm() == null
|
||||
? TrustManagerFactory.getDefaultAlgorithm()
|
||||
: tlsServerConfig.getTrustStoreAlgorithm()
|
||||
);
|
||||
sslContextFactory.setTrustStorePassword(
|
||||
tlsServerConfig.getTrustStorePasswordProvider() == null
|
||||
? null
|
||||
: tlsServerConfig.getTrustStorePasswordProvider().getPassword()
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sslContextFactory = sslContextFactoryBinding.getProvider().get();
|
||||
}
|
||||
|
|
|
@ -19,48 +19,205 @@
|
|||
|
||||
package org.apache.druid.server.security;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Throwables;
|
||||
import org.apache.druid.metadata.PasswordProvider;
|
||||
|
||||
import org.eclipse.jetty.util.ssl.AliasedX509ExtendedKeyManager;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateException;
|
||||
|
||||
public class TLSUtils
|
||||
{
|
||||
public static class ClientSSLContextBuilder
|
||||
{
|
||||
private String protocol;
|
||||
private String trustStoreType;
|
||||
private String trustStorePath;
|
||||
private String trustStoreAlgorithm;
|
||||
private PasswordProvider trustStorePasswordProvider;
|
||||
private String keyStoreType;
|
||||
private String keyStorePath;
|
||||
private String keyStoreAlgorithm;
|
||||
private String certAlias;
|
||||
private PasswordProvider keyStorePasswordProvider;
|
||||
private PasswordProvider keyManagerFactoryPasswordProvider;
|
||||
|
||||
public ClientSSLContextBuilder setProtocol(String protocol)
|
||||
{
|
||||
this.protocol = protocol;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClientSSLContextBuilder setTrustStoreType(String trustStoreType)
|
||||
{
|
||||
this.trustStoreType = trustStoreType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClientSSLContextBuilder setTrustStorePath(String trustStorePath)
|
||||
{
|
||||
this.trustStorePath = trustStorePath;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClientSSLContextBuilder setTrustStoreAlgorithm(String trustStoreAlgorithm)
|
||||
{
|
||||
this.trustStoreAlgorithm = trustStoreAlgorithm;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClientSSLContextBuilder setTrustStorePasswordProvider(PasswordProvider trustStorePasswordProvider)
|
||||
{
|
||||
this.trustStorePasswordProvider = trustStorePasswordProvider;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClientSSLContextBuilder setKeyStoreType(String keyStoreType)
|
||||
{
|
||||
this.keyStoreType = keyStoreType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClientSSLContextBuilder setKeyStorePath(String keyStorePath)
|
||||
{
|
||||
this.keyStorePath = keyStorePath;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClientSSLContextBuilder setKeyStoreAlgorithm(String keyStoreAlgorithm)
|
||||
{
|
||||
this.keyStoreAlgorithm = keyStoreAlgorithm;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClientSSLContextBuilder setCertAlias(String certAlias)
|
||||
{
|
||||
this.certAlias = certAlias;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClientSSLContextBuilder setKeyStorePasswordProvider(PasswordProvider keyStorePasswordProvider)
|
||||
{
|
||||
this.keyStorePasswordProvider = keyStorePasswordProvider;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClientSSLContextBuilder setKeyManagerFactoryPasswordProvider(PasswordProvider keyManagerFactoryPasswordProvider)
|
||||
{
|
||||
this.keyManagerFactoryPasswordProvider = keyManagerFactoryPasswordProvider;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SSLContext build()
|
||||
{
|
||||
Preconditions.checkNotNull(trustStorePath, "must specify a trustStorePath");
|
||||
|
||||
return createSSLContext(
|
||||
protocol,
|
||||
trustStoreType,
|
||||
trustStorePath,
|
||||
trustStoreAlgorithm,
|
||||
trustStorePasswordProvider,
|
||||
keyStoreType,
|
||||
keyStorePath,
|
||||
keyStoreAlgorithm,
|
||||
certAlias,
|
||||
keyStorePasswordProvider,
|
||||
keyManagerFactoryPasswordProvider
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static SSLContext createSSLContext(
|
||||
String protocol,
|
||||
String trustStoreType,
|
||||
@Nullable String protocol,
|
||||
@Nullable String trustStoreType,
|
||||
String trustStorePath,
|
||||
String trustStoreAlgorithm,
|
||||
PasswordProvider trustStorePasswordProvider
|
||||
@Nullable String trustStoreAlgorithm,
|
||||
@Nullable PasswordProvider trustStorePasswordProvider,
|
||||
@Nullable String keyStoreType,
|
||||
@Nullable String keyStorePath,
|
||||
@Nullable String keyStoreAlgorithm,
|
||||
@Nullable String certAlias,
|
||||
@Nullable PasswordProvider keyStorePasswordProvider,
|
||||
@Nullable PasswordProvider keyManagerFactoryPasswordProvider
|
||||
)
|
||||
{
|
||||
SSLContext sslContext = null;
|
||||
try {
|
||||
sslContext = SSLContext.getInstance(protocol == null ? "TLSv1.2" : protocol);
|
||||
KeyStore keyStore = KeyStore.getInstance(trustStoreType == null
|
||||
KeyStore trustStore = KeyStore.getInstance(trustStoreType == null
|
||||
? KeyStore.getDefaultType()
|
||||
: trustStoreType);
|
||||
keyStore.load(
|
||||
trustStore.load(
|
||||
new FileInputStream(trustStorePath),
|
||||
trustStorePasswordProvider.getPassword().toCharArray()
|
||||
trustStorePasswordProvider == null ? null : trustStorePasswordProvider.getPassword().toCharArray()
|
||||
);
|
||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(trustStoreAlgorithm == null
|
||||
? TrustManagerFactory.getDefaultAlgorithm()
|
||||
: trustStoreAlgorithm);
|
||||
trustManagerFactory.init(keyStore);
|
||||
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
|
||||
trustManagerFactory.init(trustStore);
|
||||
|
||||
|
||||
KeyManager[] keyManagers;
|
||||
if (keyStorePath != null) {
|
||||
KeyStore keyStore = KeyStore.getInstance(keyStoreType == null
|
||||
? KeyStore.getDefaultType()
|
||||
: keyStoreType);
|
||||
keyStore.load(
|
||||
new FileInputStream(keyStorePath),
|
||||
keyStorePasswordProvider == null ? null : keyStorePasswordProvider.getPassword().toCharArray()
|
||||
);
|
||||
|
||||
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
|
||||
keyStoreAlgorithm == null ?
|
||||
KeyManagerFactory.getDefaultAlgorithm() : keyStoreAlgorithm
|
||||
);
|
||||
keyManagerFactory.init(
|
||||
keyStore,
|
||||
keyManagerFactoryPasswordProvider == null ? null : keyManagerFactoryPasswordProvider.getPassword().toCharArray()
|
||||
);
|
||||
keyManagers = createAliasedKeyManagers(keyManagerFactory.getKeyManagers(), certAlias);
|
||||
} else {
|
||||
keyManagers = null;
|
||||
}
|
||||
|
||||
sslContext.init(
|
||||
keyManagers,
|
||||
trustManagerFactory.getTrustManagers(),
|
||||
null
|
||||
);
|
||||
}
|
||||
catch (CertificateException | KeyManagementException | IOException | KeyStoreException | NoSuchAlgorithmException e) {
|
||||
catch (CertificateException | KeyManagementException | IOException | KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e) {
|
||||
Throwables.propagate(e);
|
||||
}
|
||||
return sslContext;
|
||||
}
|
||||
|
||||
// Use Jetty's aliased KeyManager for consistency between server/client TLS configs
|
||||
private static KeyManager[] createAliasedKeyManagers(KeyManager[] delegates, String certAlias)
|
||||
{
|
||||
KeyManager[] aliasedManagers = new KeyManager[delegates.length];
|
||||
for (int i = 0; i < delegates.length; i++) {
|
||||
if (delegates[i] instanceof X509ExtendedKeyManager) {
|
||||
aliasedManagers[i] = new AliasedX509ExtendedKeyManager((X509ExtendedKeyManager) delegates[i], certAlias);
|
||||
} else {
|
||||
aliasedManagers[i] = delegates[i];
|
||||
}
|
||||
}
|
||||
return aliasedManagers;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ public class OverlordProxyServletTest
|
|||
|
||||
EasyMock.replay(druidLeaderClient, request);
|
||||
|
||||
URI uri = URI.create(new OverlordProxyServlet(druidLeaderClient).rewriteTarget(request));
|
||||
URI uri = URI.create(new OverlordProxyServlet(druidLeaderClient, null, null).rewriteTarget(request));
|
||||
Assert.assertEquals("https://overlord:port/druid/overlord/worker?param1=test¶m2=test2", uri.toString());
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.apache.druid.guice.LifecycleModule;
|
|||
import org.apache.druid.guice.ManageLifecycle;
|
||||
import org.apache.druid.guice.annotations.CoordinatorIndexingServiceHelper;
|
||||
import org.apache.druid.guice.annotations.EscalatedGlobal;
|
||||
import org.apache.druid.guice.http.JettyHttpClientModule;
|
||||
import org.apache.druid.java.util.common.concurrent.ScheduledExecutorFactory;
|
||||
import org.apache.druid.java.util.common.logger.Logger;
|
||||
import org.apache.druid.java.util.http.client.HttpClient;
|
||||
|
@ -127,6 +128,8 @@ public class CliCoordinator extends ServerRunnable
|
|||
{
|
||||
List<Module> modules = new ArrayList<>();
|
||||
|
||||
modules.add(JettyHttpClientModule.global());
|
||||
|
||||
modules.add(
|
||||
new Module()
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue