Amazon SDK未使用自定义默认SSL套接字工厂

时间:2017-12-20 19:53:04

标签: java scala ssl amazon-s3

我正在尝试使用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 Client的实例替换对公共ECS资源的Http调用,则它会因此错误而失败:

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"

因此,亚马逊SDK(或任何底层HTTP库)似乎只在应用程序启动时获取默认的SSL上下文(而不是每次创建SSL连接时都获取它,因此对运行时更改做出反应到默认的SSL上下文)。

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

为了在运行时使用自定义SSL,我们需要使用以下代码段加载ApacheClient SSL

SSLContext 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")