3

I have an AWS Lambda function that gets triggered by the Alexa command. On every Alexa command, I want to call an external API endpoint to do the desired operation.

I have a jar that calls the API and has the below externalService class with invokeCommand function. The jar has been added as a dependency under my Java project.

if(value.equals("something")) {
   externalService.invokeCommand();
   }

invokeCommand calls the external API which is protected by SSL certificate and throws an error

PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

In Elastic Beanstalk I can create a zip folder with Jar, Keystore, and procfile and I can supply keystore as an argument in the procfile which will run the jar with the keystore and that'll allow access to SSL secured endpoint.

if(value.equals("something")) {
   externalService.invokeCommand(); // error on AWS Lambda
   }

However, I don't think I can do the same with Lambda which is not allowing me to call SSL secured endpoint.

  • Is there a way I can package my jar with the trustStore?
  • Is there a way to run a jar with command-line option in AWS Lambda just like procfile does in Elastic Beanstalk.
Mr. Wonderful
  • 189
  • 4
  • 13
  • https://forums.aws.amazon.com/thread.jspa?threadID=227883&tstart=0&messageID=711968#711968 : "Hi, We appreciate your interest in Lambda and ll consider this as a feature request. Meanwhile maybe you can fork/exec and start a jvm process with the required trust store ? regards Shashank" – xerx593 Oct 18 '19 at 19:44
  • Thanks. Although the post in the link is from 2016, I wonder if it has been implemented by now. – Mr. Wonderful Oct 18 '19 at 19:50
  • 1
    according to google: not yet! ...but, thanks to the former: a blog post which handles exactly your problem/question: https://medium.com/i-me-myself-naveen/java-ssl-within-aws-lambda-39f87c1c03f2 ..and provides two working solution approaches! (i looked up "aws lambda truststore") – xerx593 Oct 18 '19 at 19:56
  • Please post the code you are using to make the request. Also, do you require certificate validation or are you OK with skipping that step as long as you can make the request? Also print the full stack trace from the exception. – Ashaman Kingpin Oct 18 '19 at 21:30
  • 2
    First, SSL certs are free anymore - you need to talk to your "External API" vendor about why they can't get a real cert installed. Second, see the accepted answer in [this post](https://stackoverflow.com/questions/2893819/accept-servers-self-signed-ssl-certificate-in-java-client) - basically do your own cert handling. – stdunbar Oct 18 '19 at 21:45
  • Thanks for the response guys and directing my search in the right direction. I was able to utilize code from [this post](https://stackoverflow.com/questions/344748/how-to-use-a-file-in-a-jar-as-javax-net-ssl-keystore) which essentially created a trust manager and installs the trust manager which is what I needed. – Mr. Wonderful Oct 20 '19 at 15:24
  • any update from aws side to handle it in lambda? – Mrityunjay May 06 '20 at 10:07

2 Answers2

1

You have too create truststore programitically See below code for reference

        // Declare path of trust store and create file
        String trustStorePath = "/tmp/trust";
        // try creating above directory and path if you get error no such file 

        // Create Truststore using Key store api
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());

        // locate the default truststore
        String filename = System.getProperty("java.home")
                + "/lib/security/cacerts".replace('/', File.separatorChar);

        try (FileInputStream fis = new FileInputStream(filename)) {

            keyStore.load(fis, "changeit".toCharArray());
        }

        // Add Certificate to Key store
        CertificateFactory certF = CertificateFactory.getInstance("X.509");
        Certificate cert = certF.generateCertificate(new FileInputStream("your certificate path"));
        keyStore.setCertificateEntry("any alias", cert);

        // Write Key Store
        try (FileOutputStream out = new FileOutputStream(trustStoreFile)) {
            keyStore.store(out, "changeit".toCharArray());
        }

        // Set Certificates to System properties
        System.setProperty("javax.net.ssl.trustStore", trustStorePath);
        System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

This you can test locally as well on aws lambda. Hope this will solve the issue

  • You can keep you certificate in s3 or keep it in resources of lambda directory
RAVI KUMAR
  • 21
  • 1
0

I believe one option would be to package the certificates into the Jar/zip for your Lambda function itself which would put them on your classpath. Once they are on your classpath you can set them up programmatically using

    System.setProperty("javax.net.ssl.keyStore", KEYSTORE_FILE);
    System.setProperty("javax.net.ssl.keyStorePassword", KEYSTORE);
    System.setProperty("javax.net.ssl.keyStoreType", "JKS");
    System.setProperty("javax.net.ssl.trustStore", TRUSTSTORE_FILE);
    System.setProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE);
    System.setProperty("javax.net.ssl.trustStoreType", "JKS");

Where you'd define KEYSTORE_FILE like

URL trustStoreResource = LdapConfig.class.getResource( "/keystore.jks" );
String KEYSTORE_FILE= trustStoreResource.toURI().getPath();
System.setProperty("javax.net.ssl.keyStore", KEYSTORE_FILE);
Mr Chow
  • 365
  • 6
  • 10