我正在尝试使用Amazon S3 SDK连接到内部ECS实例。与ECS的连接由内部CA签署的证书确保。我正在尝试通过编程方式加载一个带有CA的Java密钥库文件,但是使用Amazon SDK与ECS的连接不断与证书相关的错误失败。
com.amazonaws.SdkClientException: Unable to execute HTTP request: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
这是加载密钥库的小样本代码。:
val ks = KeyStore.getInstance(KeyStore.getDefaultType)
ks.load(this.getClass.getClassLoader.getResourceAsStream("cacerts.success"), "changeit".toCharArray)
val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm)
tmf.init(ks)
val sslContext = SSLContext.getInstance("TLSv1.2")
sslContext.init(null, tmf.getTrustManagers, null)
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory)
val response = Http("https://ecsNamespace.ecsHostname.internal.com:9021/bucketName/path/to/file").asString
因此,Http
从我创建并设置为默认的自定义SSL上下文对象使用SSL套接字工厂没有问题。
但是,亚马逊SDK确实有问题。如果我用S3客户端的实例将Http
调用替换为公共ECS资源,则在此错误中失败:
com.amazonaws.SdkClientException: Unable to execute HTTP request: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
这是代码:
val client2 = AmazonS3ClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("keyId", "secret")))
.withEndpointConfiguration(new EndpointConfiguration("https://ecsNamespace.ecsHostname.internal.com:9021", "us-east-1")) // S3 SDK requires a region, but ECS will ignore it.
.withPathStyleAccessEnabled(true)
.build()
client2.getObject("bucketName", "path/to/file")
如果我提前设置系统属性,则Amazon SDK与内部CA一起使用:
export JAVA_OPTS="-Djavax.net.ssl.trustStore=/path/to/my/cacerts.success -Djavax.net.ssl.trustStorePassword=changeit"
因此,似乎Amazon SDK(或任何基础HTTP库)仅在应用程序启动时获得默认的SSL上下文(而不是每次创建SSL连接时获得它,因此可以对运行时更改进行反应对于默认的SSL上下文)。
有什么想法?
为了在运行时使用自定义SSL,我们需要使用以下代码shippet
加载Apacheclient SSLSSLContext sslcontext = SSLContexts.custom()
.loadTrustMaterial(new File("/path/to/my/cacerts.success"), "changeit".toCharArray(),
new TrustSelfSignedStrategy())
.build();
// Allow TLSv1 protocol only add others if required
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
new String[] { "TLSv1" },
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
// Adding Custom SSL Support
config.getApacheHttpClientConfig().setSslSocketFactory(sslsf);
config.setSignerOverride("AWSS3V4SignerType");
一旦加载了证书,我们就可以与以下代码联系:
val client2 = AmazonS3ClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("keyId", "secret")))
.withEndpointConfiguration(new EndpointConfiguration("https://ecsNamespace.ecsHostname.internal.com:9021", "us-east-1"))
// S3 SDK requires a region, but ECS will ignore it.
.withPathStyleAccessEnabled(true)
.build()
可以完成此正常操作之后,例如
client2.getObject("bucketName", "path/to/file")