mirror of https://github.com/apache/jclouds.git
[docker] upgrade to docker 1.7 and refactor TLS support
This commit is contained in:
parent
4edaf18226
commit
55a7d8ce3c
|
@ -8,15 +8,11 @@ Please follow these steps to configure your workstation for jclouds-docker:
|
|||
|
||||
- install the latest Docker release (please visit https://docs.docker.com/installation/)
|
||||
|
||||
If you are using `boot2docker`, notice that from version v1.3.0 the Docker daemon is set to use an encrypted TCP
|
||||
socket (--tls, or --tlsverify),
|
||||
then you need to import CA certificate into Trusted Certs:
|
||||
|
||||
`keytool -import -trustcacerts -file /Users/andrea/.boot2docker/certs/boot2docker-vm/ca.pem -alias BOOT2DOCKER -keystore $JAVA_HOME/jre/lib/security/cacerts`
|
||||
If you are using `boot2docker` then it can also manage certificates and help you setup `DOCKER_CERT_PATH` and `DOCKER_HOST` environment variables. (See `boot2docker shellinit`)
|
||||
|
||||
by default the passoword is `changeit`
|
||||
Assuming these environment variables are setup correctly there are no further setups steps are required.
|
||||
|
||||
N.B.: From `Docker 1.3.2+` the server doesn't accept sslv3 protocol (https://github.com/docker/docker/pull/8588/files)
|
||||
Live tests then can now be run: `mvn -Plive integration-test`
|
||||
|
||||
#How it works
|
||||
|
||||
|
|
|
@ -34,10 +34,11 @@
|
|||
<packaging>bundle</packaging>
|
||||
|
||||
<properties>
|
||||
<test.docker.endpoint>https://localhost:4243</test.docker.endpoint>
|
||||
<test.docker.api-version>1.15</test.docker.api-version>
|
||||
<test.docker.identity>FIXME</test.docker.identity>
|
||||
<test.docker.credential>FIXME</test.docker.credential>
|
||||
<test.docker.api-version>1.19</test.docker.api-version>
|
||||
<test.docker.identity>${env.DOCKER_CERT_PATH}/cert.pem</test.docker.identity>
|
||||
<test.docker.credential>${env.DOCKER_CERT_PATH}/key.pem</test.docker.credential>
|
||||
<test.docker.cacert.path>${env.DOCKER_CERT_PATH}/ca.pem</test.docker.cacert.path>
|
||||
<test.jclouds.trust-all-certs>false</test.jclouds.trust-all-certs>
|
||||
<jclouds.osgi.export>org.jclouds.docker*;version="${project.version}"</jclouds.osgi.export>
|
||||
<jclouds.osgi.import>
|
||||
org.jclouds.compute.internal;version="${project.version}",
|
||||
|
@ -134,6 +135,26 @@
|
|||
<id>live</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<version>1.9.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>regex-property</id>
|
||||
<goals>
|
||||
<goal>regex-property</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<name>test.docker.endpoint</name>
|
||||
<value>${env.DOCKER_HOST}</value>
|
||||
<regex>tcp</regex>
|
||||
<replacement>https</replacement>
|
||||
<failIfNoMatch>false</failIfNoMatch>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
|
@ -149,8 +170,10 @@
|
|||
<systemPropertyVariables>
|
||||
<test.docker.endpoint>${test.docker.endpoint}</test.docker.endpoint>
|
||||
<test.docker.api-version>${test.docker.api-version}</test.docker.api-version>
|
||||
<test.docker.credential>${test.docker.identity}</test.docker.credential>
|
||||
<test.docker.identity>${test.docker.identity}</test.docker.identity>
|
||||
<test.docker.credential>${test.docker.credential}</test.docker.credential>
|
||||
<test.docker.cacert.path>${test.docker.cacert.path}</test.docker.cacert.path>
|
||||
<test.jclouds.trust-all-certs>${test.jclouds.trust-all-certs}</test.jclouds.trust-all-certs>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
|
|
@ -37,6 +37,8 @@ import static org.jclouds.reflect.Reflection2.typeToken;
|
|||
@AutoService(ApiMetadata.class)
|
||||
public class DockerApiMetadata extends BaseHttpApiMetadata<DockerApi> {
|
||||
|
||||
public static final String DOCKER_CA_CERT_PATH = "docker.cacert.path";
|
||||
|
||||
@Override
|
||||
public Builder toBuilder() {
|
||||
return new Builder().fromApiMetadata(this);
|
||||
|
@ -55,6 +57,7 @@ public class DockerApiMetadata extends BaseHttpApiMetadata<DockerApi> {
|
|||
properties.setProperty(Constants.PROPERTY_CONNECTION_TIMEOUT, "1200000"); // 15 minutes
|
||||
properties.setProperty(ComputeServiceProperties.IMAGE_LOGIN_USER, "root:password");
|
||||
properties.setProperty(TEMPLATE, "osFamily=UBUNTU,os64Bit=true");
|
||||
properties.setProperty(DOCKER_CA_CERT_PATH, "");
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,14 @@
|
|||
*/
|
||||
package org.jclouds.docker.config;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.TypeLiteral;
|
||||
import com.google.inject.name.Names;
|
||||
import com.google.inject.util.Modules;
|
||||
import org.jclouds.docker.DockerApi;
|
||||
import org.jclouds.docker.handlers.DockerErrorHandler;
|
||||
import org.jclouds.docker.suppliers.DockerUntrustedSSLContextSupplier;
|
||||
import org.jclouds.http.HttpErrorHandler;
|
||||
import org.jclouds.http.annotation.ClientError;
|
||||
import org.jclouds.http.annotation.Redirection;
|
||||
|
@ -28,6 +34,8 @@ import org.jclouds.http.okhttp.config.OkHttpCommandExecutorServiceModule;
|
|||
import org.jclouds.rest.ConfiguresHttpApi;
|
||||
import org.jclouds.rest.config.HttpApiModule;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
/**
|
||||
* Configures the Docker connection.
|
||||
*/
|
||||
|
@ -48,8 +56,13 @@ public class DockerHttpApiModule extends HttpApiModule<DockerApi> {
|
|||
@Override
|
||||
protected void configure() {
|
||||
super.configure();
|
||||
install(new OkHttpCommandExecutorServiceModule());
|
||||
install(Modules.override(new OkHttpCommandExecutorServiceModule()).with(new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(new TypeLiteral<Supplier<SSLContext>>() {}).annotatedWith(Names.named("untrusted")).to(DockerUntrustedSSLContextSupplier.class);
|
||||
}
|
||||
}));
|
||||
bind(OkHttpClientSupplier.class).to(DockerOkHttpClientSupplier.class);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ package org.jclouds.docker.config;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.docker.suppliers.SSLContextWithKeysSupplier;
|
||||
import org.jclouds.docker.suppliers.DockerSSLContextSupplier;
|
||||
import org.jclouds.http.okhttp.OkHttpClientSupplier;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
@ -30,24 +30,24 @@ import com.squareup.okhttp.TlsVersion;
|
|||
@Singleton
|
||||
public class DockerOkHttpClientSupplier implements OkHttpClientSupplier {
|
||||
|
||||
private final SSLContextWithKeysSupplier sslContextWithKeysSupplier;
|
||||
private final DockerSSLContextSupplier dockerSSLContextSupplier;
|
||||
|
||||
@Inject
|
||||
DockerOkHttpClientSupplier(SSLContextWithKeysSupplier sslContextWithKeysSupplier) {
|
||||
this.sslContextWithKeysSupplier = sslContextWithKeysSupplier;
|
||||
}
|
||||
@Inject
|
||||
DockerOkHttpClientSupplier(DockerSSLContextSupplier dockerSSLContextSupplier) {
|
||||
this.dockerSSLContextSupplier = dockerSSLContextSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OkHttpClient get() {
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
ConnectionSpec tlsSpec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
||||
.tlsVersions(TlsVersion.TLS_1_0, TlsVersion.TLS_1_1, TlsVersion.TLS_1_2)
|
||||
.build();
|
||||
ConnectionSpec cleartextSpec = new ConnectionSpec.Builder(ConnectionSpec.CLEARTEXT)
|
||||
.build();
|
||||
client.setConnectionSpecs(ImmutableList.of(tlsSpec, cleartextSpec));
|
||||
client.setSslSocketFactory(sslContextWithKeysSupplier.get().getSocketFactory());
|
||||
return client;
|
||||
}
|
||||
@Override
|
||||
public OkHttpClient get() {
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
ConnectionSpec tlsSpec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
||||
.tlsVersions(TlsVersion.TLS_1_0, TlsVersion.TLS_1_1, TlsVersion.TLS_1_2)
|
||||
.build();
|
||||
ConnectionSpec cleartextSpec = new ConnectionSpec.Builder(ConnectionSpec.CLEARTEXT)
|
||||
.build();
|
||||
client.setConnectionSpecs(ImmutableList.of(tlsSpec, cleartextSpec));
|
||||
client.setSslSocketFactory(dockerSSLContextSupplier.get().getSocketFactory());
|
||||
return client;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -101,8 +101,6 @@ public abstract class Config {
|
|||
|
||||
@Nullable public abstract String networkMode();
|
||||
|
||||
public abstract Map<String, String> devices();
|
||||
|
||||
Config() {
|
||||
}
|
||||
|
||||
|
@ -112,7 +110,7 @@ public abstract class Config {
|
|||
"AttachStderr", "Tty", "OpenStdin", "StdinOnce", "Env", "Cmd", "Entrypoint", "Image", "Volumes",
|
||||
"WorkingDir", "NetworkDisabled", "ExposedPorts", "SecurityOpts", "HostConfig", "Binds", "Links",
|
||||
"LxcConf", "PortBindings", "PublishAllPorts", "Privileged", "Dns", "DnsSearch", "VolumesFrom",
|
||||
"CapAdd", "CapDrop", "RestartPolicy", "NetworkMode", "Devices"
|
||||
"CapAdd", "CapDrop", "RestartPolicy", "NetworkMode"
|
||||
})
|
||||
public static Config create(String hostname, String domainname, String user, int memory, int memorySwap,
|
||||
int cpuShares, boolean attachStdin, boolean attachStdout, boolean attachStderr, boolean tty,
|
||||
|
@ -121,13 +119,12 @@ public abstract class Config {
|
|||
Map<String, ?> exposedPorts, List<String> securityOpts, HostConfig hostConfig, List<String> binds,
|
||||
List<String> links, List<Map<String, String>> lxcConf, Map<String, List<Map<String, String>>> portBindings,
|
||||
boolean publishAllPorts, boolean privileged, List<String> dns, String dnsSearch, String volumesFrom,
|
||||
List<String> capAdd, List<String> capDrop, Map<String, String> restartPolicy, String networkMode, Map<String, String> devices) {
|
||||
List<String> capAdd, List<String> capDrop, Map<String, String> restartPolicy, String networkMode) {
|
||||
return new AutoValue_Config(hostname, domainname, user, memory, memorySwap, cpuShares, attachStdin,
|
||||
attachStdout, attachStderr, tty, openStdin, stdinOnce, copyOf(env), copyOf(cmd), copyOf(entrypoint),
|
||||
image, copyOf(volumes), workingDir, networkDisabled, copyOf(exposedPorts), copyOf(securityOpts), hostConfig,
|
||||
copyOf(binds), copyOf(links), copyOf(lxcConf), copyOf(portBindings), publishAllPorts, privileged,
|
||||
copyOf(dns), dnsSearch, volumesFrom, copyOf(capAdd), copyOf(capDrop), copyOf(restartPolicy), networkMode,
|
||||
copyOf(devices));
|
||||
copyOf(dns), dnsSearch, volumesFrom, copyOf(capAdd), copyOf(capDrop), copyOf(restartPolicy), networkMode);
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
|
@ -174,7 +171,6 @@ public abstract class Config {
|
|||
private List<String> capDrop = Lists.newArrayList();
|
||||
private Map<String, String> restartPolicy = Maps.newHashMap();
|
||||
private String networkMode;
|
||||
private Map<String, String> devices = Maps.newHashMap();
|
||||
|
||||
public Builder hostname(String hostname) {
|
||||
this.hostname = hostname;
|
||||
|
@ -191,18 +187,24 @@ public abstract class Config {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder memory(int memory) {
|
||||
this.memory = memory;
|
||||
public Builder memory(Integer memory) {
|
||||
if (memory != null) {
|
||||
this.memory = memory;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder memorySwap(int memorySwap) {
|
||||
this.memorySwap = memorySwap;
|
||||
public Builder memorySwap(Integer memorySwap) {
|
||||
if (memorySwap != null) {
|
||||
this.memorySwap = memorySwap;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder cpuShares(int cpuShares) {
|
||||
this.cpuShares = cpuShares;
|
||||
public Builder cpuShares(Integer cpuShares) {
|
||||
if (cpuShares != null) {
|
||||
this.cpuShares = cpuShares;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -351,17 +353,12 @@ public abstract class Config {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder devices(Map<String, String> devices) {
|
||||
this.devices = devices;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Config build() {
|
||||
return Config.create(hostname, domainname, user, memory, memorySwap, cpuShares, attachStdin, attachStdout,
|
||||
attachStderr, tty, openStdin, stdinOnce, env, cmd, entrypoint, image, volumes, workingDir,
|
||||
networkDisabled, exposedPorts, securityOpts, hostConfig, binds, links, lxcConf, portBindings,
|
||||
publishAllPorts, privileged, dns, dnsSearch, volumesFrom, capAdd, capDrop, restartPolicy,
|
||||
networkMode, devices);
|
||||
networkMode);
|
||||
}
|
||||
|
||||
public Builder fromConfig(Config in) {
|
||||
|
@ -373,7 +370,7 @@ public abstract class Config {
|
|||
.hostConfig(in.hostConfig()).binds(in.binds()).links(in.links()).lxcConf(in.lxcConf())
|
||||
.portBindings(in.portBindings()).publishAllPorts(in.publishAllPorts()).privileged(in.privileged())
|
||||
.dns(in.dns()).dnsSearch(in.dnsSearch()).volumesFrom(in.volumesFrom()).capAdd(in.capAdd())
|
||||
.capDrop(in.capDrop()).restartPolicy(in.restartPolicy()).networkMode(in.networkMode()).devices(in.devices());
|
||||
.capDrop(in.capDrop()).restartPolicy(in.restartPolicy()).networkMode(in.networkMode());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ public abstract class Info {
|
|||
|
||||
public abstract int containers();
|
||||
|
||||
public abstract int debug();
|
||||
public abstract boolean debug();
|
||||
|
||||
public abstract String driver();
|
||||
|
||||
|
@ -36,7 +36,7 @@ public abstract class Info {
|
|||
|
||||
public abstract String executionDriver();
|
||||
|
||||
public abstract int iPv4Forwarding();
|
||||
public abstract boolean iPv4Forwarding();
|
||||
|
||||
public abstract int images();
|
||||
|
||||
|
@ -48,7 +48,7 @@ public abstract class Info {
|
|||
|
||||
public abstract String kernelVersion();
|
||||
|
||||
public abstract int memoryLimit();
|
||||
public abstract boolean memoryLimit();
|
||||
|
||||
public abstract int nEventsListener();
|
||||
|
||||
|
@ -58,7 +58,7 @@ public abstract class Info {
|
|||
|
||||
public abstract String operatingSystem();
|
||||
|
||||
public abstract int swapLimit();
|
||||
public abstract boolean swapLimit();
|
||||
|
||||
public abstract String dockerRootDir();
|
||||
|
||||
|
@ -96,10 +96,10 @@ public abstract class Info {
|
|||
"NFd", "NGoroutines", "OperatingSystem", "SwapLimit", "DockerRootDir", "Labels", "MemTotal", "NCPU",
|
||||
"ID", "Name"
|
||||
})
|
||||
public static Info create(int containers, int debug, String driver, List<List<String>> driverStatus,
|
||||
String executionDriver, int iPv4Forwarding, int images, String indexServerAddress,
|
||||
String initPath, String initSha1, String kernelVersion, int memoryLimit,
|
||||
int nEventsListener, int nFd, int nGoroutines, String operatingSystem, int swapLimit,
|
||||
public static Info create(int containers, boolean debug, String driver, List<List<String>> driverStatus,
|
||||
String executionDriver, boolean iPv4Forwarding, int images, String indexServerAddress,
|
||||
String initPath, String initSha1, String kernelVersion, boolean memoryLimit,
|
||||
int nEventsListener, int nFd, int nGoroutines, String operatingSystem, boolean swapLimit,
|
||||
String dockerRootDir, List<String> labels, long memTotal, int ncpu, String id, String name) {
|
||||
return new AutoValue_Info(containers, debug, driver, driverStatus, executionDriver, iPv4Forwarding, images,
|
||||
indexServerAddress, initPath, initSha1, kernelVersion, memoryLimit, nEventsListener, nFd, nGoroutines,
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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 org.jclouds.docker.suppliers;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.base.Supplier;
|
||||
import org.jclouds.docker.DockerApiMetadata;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.location.Provider;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Throwables.propagate;
|
||||
|
||||
@Singleton
|
||||
public class DockerSSLContextSupplier implements Supplier<SSLContext> {
|
||||
private final Supplier<Credentials> creds;
|
||||
private final String caCertPath;
|
||||
|
||||
|
||||
@Inject
|
||||
DockerSSLContextSupplier(@Provider Supplier<Credentials> creds, @Named(DockerApiMetadata.DOCKER_CA_CERT_PATH) String caCertPath) {
|
||||
this.creds = creds;
|
||||
this.caCertPath = caCertPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLContext get() {
|
||||
Credentials currentCreds = checkNotNull(creds.get(), "credential supplier returned null");
|
||||
try {
|
||||
SSLContextBuilder builder = new SSLContextBuilder();
|
||||
builder.clientKeyAndCertificate(currentCreds.credential, currentCreds.identity);
|
||||
if (!Strings.isNullOrEmpty(caCertPath)) {
|
||||
builder.caCertificate(caCertPath);
|
||||
}
|
||||
return builder.build();
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw propagate(e);
|
||||
} catch (IOException e) {
|
||||
throw propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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 org.jclouds.docker.suppliers;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.http.config.SSLModule;
|
||||
import org.jclouds.location.Provider;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Throwables.propagate;
|
||||
|
||||
@Singleton
|
||||
public class DockerUntrustedSSLContextSupplier implements Supplier<SSLContext> {
|
||||
private final Supplier<Credentials> creds;
|
||||
private final SSLModule.TrustAllCerts insecureTrustManager;
|
||||
|
||||
|
||||
@Inject
|
||||
DockerUntrustedSSLContextSupplier(@Provider Supplier<Credentials> creds, SSLModule.TrustAllCerts insecureTrustManager) {
|
||||
this.creds = creds;
|
||||
this.insecureTrustManager = insecureTrustManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLContext get() {
|
||||
Credentials currentCreds = checkNotNull(creds.get(), "credential supplier returned null");
|
||||
try {
|
||||
SSLContextBuilder builder = new SSLContextBuilder();
|
||||
builder.clientKeyAndCertificate(currentCreds.credential, currentCreds.identity);
|
||||
builder.trustManager(insecureTrustManager);
|
||||
return builder.build();
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw propagate(e);
|
||||
} catch (IOException e) {
|
||||
throw propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* 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 org.jclouds.docker.suppliers;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.io.Files;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.openssl.PEMKeyPair;
|
||||
import org.bouncycastle.openssl.PEMParser;
|
||||
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
|
||||
import org.jclouds.util.Closeables2;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.net.Socket;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyStore;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.Principal;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Security;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import static com.google.common.base.Throwables.propagate;
|
||||
|
||||
public class SSLContextBuilder {
|
||||
|
||||
private KeyManager[] keyManagers;
|
||||
private TrustManager[] trustManagers;
|
||||
|
||||
public SSLContextBuilder() { }
|
||||
|
||||
public SSLContextBuilder clientKeyAndCertificate(String keyPath, String certPath) throws IOException, CertificateException {
|
||||
X509Certificate certificate = getCertificate(loadFile(certPath));
|
||||
PrivateKey privateKey = getKey(loadFile(keyPath));
|
||||
keyManagers = new KeyManager[]{new InMemoryKeyManager(certificate, privateKey)};
|
||||
return this;
|
||||
}
|
||||
|
||||
public SSLContextBuilder caCertificate(String caCertPath){
|
||||
trustManagers = getTrustManagerWithCaCert(caCertPath);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SSLContextBuilder trustManager(TrustManager trustManager) {
|
||||
trustManagers = new TrustManager[]{trustManager};
|
||||
return this;
|
||||
}
|
||||
|
||||
public SSLContext build() throws NoSuchAlgorithmException, KeyManagementException {
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
sslContext.init(keyManagers, trustManagers, new SecureRandom());
|
||||
return sslContext;
|
||||
}
|
||||
|
||||
private TrustManager[] getTrustManagerWithCaCert(String caCertPath) {
|
||||
try {
|
||||
X509Certificate caCert = getCertificate(loadFile(caCertPath));
|
||||
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
trustStore.load(null, null);
|
||||
trustStore.setCertificateEntry("ca", caCert);
|
||||
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
tmf.init(trustStore);
|
||||
return tmf.getTrustManagers();
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw propagate(e);
|
||||
} catch (IOException e) {
|
||||
throw propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static X509Certificate getCertificate(String certificate) {
|
||||
try {
|
||||
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(
|
||||
new ByteArrayInputStream(certificate.getBytes(Charsets.UTF_8)));
|
||||
} catch (CertificateException ex) {
|
||||
throw new RuntimeException("Invalid certificate", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static PrivateKey getKey(String privateKey) {
|
||||
PEMParser pemParser = new PEMParser(new StringReader(privateKey));
|
||||
try {
|
||||
Object object = pemParser.readObject();
|
||||
if (Security.getProvider("BC") == null) {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
}
|
||||
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
|
||||
KeyPair keyPair = converter.getKeyPair((PEMKeyPair) object);
|
||||
return keyPair.getPrivate();
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException("Invalid private key", ex);
|
||||
} finally {
|
||||
Closeables2.closeQuietly(pemParser);
|
||||
}
|
||||
}
|
||||
|
||||
private static String loadFile(final String filePath) throws IOException {
|
||||
return Files.toString(new File(filePath), Charsets.UTF_8);
|
||||
}
|
||||
|
||||
private static class InMemoryKeyManager extends X509ExtendedKeyManager {
|
||||
private static final String DEFAULT_ALIAS = "docker";
|
||||
|
||||
private final X509Certificate certificate;
|
||||
|
||||
private final PrivateKey privateKey;
|
||||
|
||||
public InMemoryKeyManager(final X509Certificate certificate, final PrivateKey privateKey)
|
||||
throws IOException, CertificateException {
|
||||
this.certificate = certificate;
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseClientAlias(final String[] keyType, final Principal[] issuers,
|
||||
final Socket socket) {
|
||||
return DEFAULT_ALIAS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseServerAlias(final String keyType, final Principal[] issuers,
|
||||
final Socket socket) {
|
||||
return DEFAULT_ALIAS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getCertificateChain(final String alias) {
|
||||
return new X509Certificate[]{certificate};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getClientAliases(final String keyType, final Principal[] issuers) {
|
||||
return new String[]{DEFAULT_ALIAS};
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrivateKey getPrivateKey(final String alias) {
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getServerAliases(final String keyType, final Principal[] issuers) {
|
||||
return new String[]{DEFAULT_ALIAS};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,166 +0,0 @@
|
|||
/*
|
||||
* 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 org.jclouds.docker.suppliers;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Throwables.propagate;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.net.Socket;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.Principal;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Security;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509ExtendedKeyManager;
|
||||
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.openssl.PEMKeyPair;
|
||||
import org.bouncycastle.openssl.PEMParser;
|
||||
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
|
||||
import org.jclouds.domain.Credentials;
|
||||
import org.jclouds.http.HttpUtils;
|
||||
import org.jclouds.http.config.SSLModule.TrustAllCerts;
|
||||
import org.jclouds.location.Provider;
|
||||
import org.jclouds.util.Closeables2;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.io.Files;
|
||||
|
||||
@Singleton
|
||||
public class SSLContextWithKeysSupplier implements Supplier<SSLContext> {
|
||||
private final TrustManager[] trustManager;
|
||||
private final Supplier<Credentials> creds;
|
||||
|
||||
@Inject
|
||||
SSLContextWithKeysSupplier(@Provider Supplier<Credentials> creds, HttpUtils utils, TrustAllCerts trustAllCerts) {
|
||||
this.trustManager = utils.trustAllCerts() ? new TrustManager[]{trustAllCerts} : null;
|
||||
this.creds = creds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLContext get() {
|
||||
Credentials currentCreds = checkNotNull(creds.get(), "credential supplier returned null");
|
||||
try {
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
X509Certificate certificate = getCertificate(loadFile(currentCreds.identity));
|
||||
PrivateKey privateKey = getKey(loadFile(currentCreds.credential));
|
||||
sslContext.init(new KeyManager[]{new InMemoryKeyManager(certificate, privateKey)}, trustManager, new SecureRandom());
|
||||
return sslContext;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw propagate(e);
|
||||
} catch (KeyManagementException e) {
|
||||
throw propagate(e);
|
||||
} catch (CertificateException e) {
|
||||
throw propagate(e);
|
||||
} catch (IOException e) {
|
||||
throw propagate(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static X509Certificate getCertificate(String certificate) {
|
||||
try {
|
||||
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(
|
||||
new ByteArrayInputStream(certificate.getBytes(Charsets.UTF_8)));
|
||||
} catch (CertificateException ex) {
|
||||
throw new RuntimeException("Invalid certificate", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static PrivateKey getKey(String privateKey) {
|
||||
PEMParser pemParser = new PEMParser(new StringReader(privateKey));
|
||||
try {
|
||||
Object object = pemParser.readObject();
|
||||
if (Security.getProvider("BC") == null) {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
}
|
||||
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
|
||||
KeyPair keyPair = converter.getKeyPair((PEMKeyPair) object);
|
||||
return keyPair.getPrivate();
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException("Invalid private key", ex);
|
||||
} finally {
|
||||
Closeables2.closeQuietly(pemParser);
|
||||
}
|
||||
}
|
||||
|
||||
private static String loadFile(final String filePath) throws IOException {
|
||||
return Files.toString(new File(filePath), Charsets.UTF_8);
|
||||
}
|
||||
|
||||
private static class InMemoryKeyManager extends X509ExtendedKeyManager {
|
||||
private static final String DEFAULT_ALIAS = "docker";
|
||||
|
||||
private final X509Certificate certificate;
|
||||
|
||||
private final PrivateKey privateKey;
|
||||
|
||||
public InMemoryKeyManager(final X509Certificate certificate, final PrivateKey privateKey)
|
||||
throws IOException, CertificateException {
|
||||
this.certificate = certificate;
|
||||
this.privateKey = privateKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseClientAlias(final String[] keyType, final Principal[] issuers,
|
||||
final Socket socket) {
|
||||
return DEFAULT_ALIAS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseServerAlias(final String keyType, final Principal[] issuers,
|
||||
final Socket socket) {
|
||||
return DEFAULT_ALIAS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getCertificateChain(final String alias) {
|
||||
return new X509Certificate[]{certificate};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getClientAliases(final String keyType, final Principal[] issuers) {
|
||||
return new String[]{DEFAULT_ALIAS};
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrivateKey getPrivateKey(final String alias) {
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getServerAliases(final String keyType, final Principal[] issuers) {
|
||||
return new String[]{DEFAULT_ALIAS};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -29,6 +29,7 @@ import org.jboss.shrinkwrap.api.GenericArchive;
|
|||
import org.jboss.shrinkwrap.api.ShrinkWrap;
|
||||
import org.jboss.shrinkwrap.api.asset.ClassLoaderAsset;
|
||||
import org.jboss.shrinkwrap.api.exporter.TarExporter;
|
||||
import org.jclouds.Constants;
|
||||
import org.jclouds.apis.BaseApiLiveTest;
|
||||
import org.jclouds.compute.config.ComputeServiceProperties;
|
||||
import org.jclouds.docker.DockerApi;
|
||||
|
@ -56,8 +57,9 @@ public class BaseDockerApiLiveTest extends BaseApiLiveTest<DockerApi> {
|
|||
@Override
|
||||
protected Properties setupProperties() {
|
||||
Properties overrides = super.setupProperties();
|
||||
overrides.setProperty("jclouds.trust-all-certs", "false");
|
||||
overrides.setProperty(ComputeServiceProperties.IMAGE_LOGIN_USER, "root:password");
|
||||
setIfTestSystemPropertyPresent(overrides, provider + ".cacert.path");
|
||||
setIfTestSystemPropertyPresent(overrides, Constants.PROPERTY_TRUST_ALL_CERTS);
|
||||
return overrides;
|
||||
}
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ public class ContainerApiLiveTest extends BaseDockerApiLiveTest {
|
|||
@Test(dependsOnMethods = "testRestartContainer")
|
||||
public void testWaitContainer() {
|
||||
api().stopContainer(container.id(), 1);
|
||||
assertEquals(api().wait(container.id()).statusCode(), -1);
|
||||
assertEquals(api().wait(container.id()).statusCode(), 137);
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = "testWaitContainer")
|
||||
|
|
|
@ -40,25 +40,25 @@ public class InfoParseTest extends BaseDockerParseTest<Info> {
|
|||
public Info expected() {
|
||||
return Info.create(
|
||||
0, // containers
|
||||
1, // debug
|
||||
true, // debug
|
||||
"aufs", // driver
|
||||
ImmutableList.<List<String>>of(
|
||||
ImmutableList.of("Root Dir", "/mnt/sda1/var/lib/docker/aufs"),
|
||||
ImmutableList.of("Dirs", "46")
|
||||
), // driverStatus
|
||||
"native-0.2", // ExecutionDriver
|
||||
1, // IPv4Forwarding
|
||||
true, // IPv4Forwarding
|
||||
46, // Images
|
||||
"https://index.docker.io/v1/", // IndexServerAddress
|
||||
"/usr/local/bin/docker", // InitPath
|
||||
"", // InitSha1
|
||||
"3.16.7-tinycore64", // KernelVersion
|
||||
1, // MemoryLimit
|
||||
true, // MemoryLimit
|
||||
0, // NEventsListener
|
||||
10, // NFd
|
||||
11, // NGoroutines
|
||||
"Boot2Docker 1.4.1 (TCL 5.4); master : 86f7ec8 - Tue Dec 16 23:11:29 UTC 2014", // OperatingSystem
|
||||
1, // SwapLimit
|
||||
true, // SwapLimit
|
||||
"/mnt/sda1/var/lib/docker", // DockerRootDir
|
||||
null, // Labels
|
||||
2105585664, // MemTotal
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"Containers": 0,
|
||||
"Debug": 1,
|
||||
"Debug": true,
|
||||
"DockerRootDir": "/mnt/sda1/var/lib/docker",
|
||||
"Driver": "aufs",
|
||||
"DriverStatus": [
|
||||
|
@ -15,7 +15,7 @@
|
|||
],
|
||||
"ExecutionDriver": "native-0.2",
|
||||
"ID": "7V5Y:IQ2M:HWIL:AZJV:HKRD:Q7OZ:3EQA:ZHMO:4LAD:OSIY:YBAA:BSX6",
|
||||
"IPv4Forwarding": 1,
|
||||
"IPv4Forwarding": true,
|
||||
"Images": 46,
|
||||
"IndexServerAddress": "https://index.docker.io/v1/",
|
||||
"InitPath": "/usr/local/bin/docker",
|
||||
|
@ -23,12 +23,12 @@
|
|||
"KernelVersion": "3.16.7-tinycore64",
|
||||
"Labels": null,
|
||||
"MemTotal": 2105585664,
|
||||
"MemoryLimit": 1,
|
||||
"MemoryLimit": true,
|
||||
"NCPU": 8,
|
||||
"NEventsListener": 0,
|
||||
"NFd": 10,
|
||||
"NGoroutines": 11,
|
||||
"Name": "boot2docker",
|
||||
"OperatingSystem": "Boot2Docker 1.4.1 (TCL 5.4); master : 86f7ec8 - Tue Dec 16 23:11:29 UTC 2014",
|
||||
"SwapLimit": 1
|
||||
"SwapLimit": true
|
||||
}
|
Loading…
Reference in New Issue