Ognjen Mišić
Ognjen Mišić

Reputation: 1416

AWS Java SDK SSL Certificates

I have a JBoss AS7 connecting to AWS and specifically to S3 over the AWS SDK for Java, I have the access and secret keys, and everything runs fine. I use the S3 for various file sharing.

The JBoss' datasource connects to AWS RDS. I've enabled SSL encryption for the datasource - I have the rds-ca-2019-root.pem in my truststore configured in my standalone.xml, and my RDS datasource connects and verifies the SSL with no problem. However, when I try to connect to S3 over the SDK (when the truststore with the RDS cert is enabled), I get the following exception:

Caused by: 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

So, no truststore enabled: I can connect to S3 through SDK just fine. When I enable the truststore with the RDS certificate: my SDK -> S3 connection breaks.

I can't figure out what certificate I need to add to the truststore so that the SDK can work, or do I need to configure the SDK to use TLS somehow?

Upvotes: 8

Views: 15664

Answers (4)

laffuste
laffuste

Reputation: 17085

For AWS SDK for Java 2.x:

  1. Allow client configuration by adding apache-client dependency (as explained in the official docs)

    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>s3</artifactId>
        <version>${awssdk.version}</version>
    </dependency>
    
    <!-- By adding the apache-client dependency, ApacheHttpClient will be added 
         to the compile classpath so you can configure it. -->
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>apache-client</artifactId>
        <version>${awssdk.version}</version>
    </dependency>
    
  2. Use your own implementation to build a TrustManager (e.g. this SO question)

    TrustManager tm = getTrustManager(truststorePath, Password);  // TODO
    
  3. Add the TrustManager in your client

    S3Client client = S3Client.builder()
            .region(region)
            .credentialsProvider(StaticCredentialsProvider.create(credentials))
            .httpClientBuilder(
                    ApacheHttpClient.builder()
                            .tlsTrustManagersProvider(() -> new TrustManager[]{tm})
            )
            .build();
    

Upvotes: 1

Asanka Herath
Asanka Herath

Reputation: 1611

Ognjen's answer helped me to troubleshoot this issue. I had same problem and the issue was due to AWS SDK using custom truststore that I built for RDS connection. I had specified the custom truststore by setting javax.net.ssl.trustStore parameter explicitly.

The solution I applied: I used the script in this documentation to import the rds-combined-ca-bundle.pem into the $JAVA_HOME/lib/security/cacerts (You may find this cacerts file inside the jre/lib/security folder if you have the JDK installed.). Then I removed the javax.net.ssl.trustStore setting that I had. Then java started using the default cacerts file and now all is good.

The default password for java default truststore is changeit.

Upvotes: 5

lu_ko
lu_ko

Reputation: 4285

Ognjen and Asanka propose to use the same truststore for whole application (or application server) that is not suitable in some cases. But AWS Java SDK provides ApacheHttpClientConfig via ClientConfiguration to affect Apache HTTP client, e.g.:

import com.amazonaws.ApacheHttpClientConfig;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.http.conn.ssl.SdkTLSSocketFactory;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import org.apache.http.conn.socket.ConnectionSocketFactory;

SSLContext myContext = ...
HostnameVerifier myVerifier = ...

ConnectionSocketFactory factory = new SdkTLSSocketFactory(myContext, myVerifier);

ClientConfiguration clientConfiguration = new ClientConfiguration();
clientConfiguration.getApacheHttpClientConfig().setSslSocketFactory(factory);

AmazonS3 s3client = AmazonS3ClientBuilder.standard()
    .withClientConfiguration(clientConfiguration)
    .build();

Edit: See also StackOverflow question #47913449.

Upvotes: 1

Ognjen Mišić
Ognjen Mišić

Reputation: 1416

So I figured out what was wrong: not having any sort of custom truststore defined for my jboss meant that the AWS SDK pulled the regular cacerts truststore from $JAVA_HOME/lib/security/cacerts. Defining my own truststore (which lacked all the certificates from the cacerts truststore) - meant that AWS SDK had nowhere to fetch the regular certificates.

So to solve it: I imported my rds-ca-2019-root.pem into the above mentioned cacerts file and linked that as my server truststore in my standalone.xml.

Upvotes: 1

Related Questions