我正在尝试使用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上下文)。
有什么想法吗?
答案 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")