"Unable to execute HTTP request: Connect to <bucket-name>.s3.amazonaws.com:443 failed: connect timed out

Kshitiz Sharma picture Kshitiz Sharma · Feb 8, 2019 · Viewed 11.7k times · Source

I am trying to write a Lambda function in java which connects to S3 and then fetch the data.

When I run it locally, using main function it works fine and returns the result. Buit when I upload it to AWS lambda and the run it, I get this error message:

"errorMessage": "Unable to execute HTTP request: Connect to bucket-name.s3.amazonaws.com:443 [bucket-name.s3.amazonaws.com/52.217.1.172] failed: connect timed out", "errorType": "com.amazonaws.SdkClientException",

I have my S3 bucket as public.

My pom.xml:

<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk</artifactId>
<version>1.11.493</version>
</dependency>
      <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpcore</artifactId>
       </dependency>

 <dependency>
           <groupId>com.amazonaws</groupId>
           <artifactId>aws-lambda-java-core</artifactId>
           <version>1.1.0</version>
      </dependency>

My request Handler:

public class LambdaRequestHandler implements RequestHandler<String, String>{

@Autowired
public ClaimSuffixNumberService csService;

@Override
public String handleRequest(String input, Context context) {
    // TODO Auto-generated method stub

    if(csService==null) {
        csService= Application.getBean(ClaimSuffixNumberService.class);
    }
    String result= csService.readAndMakeCall("claimSuffix");
    return result;
}



}

My service

public String getObject(String fileName) {
System.out.println("Inside Get Object");

    try {
        BasicAWSCredentials awsCreds = new BasicAWSCredentials("access-key","secret-key");


        AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                                .withRegion(Regions.US_EAST_1)
                                .withCredentials(new AWSStaticCredentialsProvider(awsCreds))
                                .build();

        System.out.println(s3Client);

        S3Object s3object = s3Client.getObject(new GetObjectRequest(bucket-name, object-name));


        InputStream is = s3object.getObjectContent();

        String content = StreamUtils.copyToString(is, 
 StandardCharsets.UTF_8);

        return content;

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return null;
}





public String readAndMakeCall(String fileName) {
// TODO Auto-generated method stub
try {
    System.out.println("Reading for " + fileName);
    String content = getObject(fileName);

    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);

    List<ClaimSuffixNumber> claimSuffixList = mapper.readValue(content, mapper.getTypeFactory().constructCollectionType(List.class, ClaimSuffixNumber.class));
    System.out.println(claimSuffixList.toString());
    for(ClaimSuffixNumber i: claimSuffixList)
    {
        System.out.println(i);
    }
    return claimSuffixList.toString();

} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
return " ";
}

Answer

JavierCastro picture JavierCastro · Apr 3, 2020

Like Mario said, your Lambda currently has no internet access. This is most likely because of your VPC configuration. I believe Mario's answer is correct. You can setup a S3 VPC endpoint. In my case, since I was working with SES and Lambda, you can't setup an endpoint for SES, so I'm adding a workaround using NAT Gateway. (NOTE: NAT Gateway does NOT have a free tier)

  • Go into the VPC console, into the Subnets menu and create a new subnet in the VPC where you have your Lambda function.
  • Next, go into the NAT Gateways menu and create a NAT Gateway. Choose a subnet that has internet access (not the new one) and is in the same VPC. You can check if a subnet has internet access by going to the subnet menu, choosing a subnet and clicking the Route Table tab. If it has internet access you should see something like:
|---------------------|------------------|
|     Destination     |      Target      |
|---------------------|------------------|
|     0.0.0.0/0       |     igw-####     |
|---------------------|------------------|
  • Next, go to the Route Tables menu and create a new route table. Make sure it's in the same VPC. When you create a new one, it comes with an internet gateway route by default so click the Routes tab and replace that route a new one pointing to your NAT Gateway. It should look like this:
|---------------------|------------------|
|     Destination     |      Target      |
|---------------------|------------------|
|     0.0.0.0/0       |     nat-####     |
|---------------------|------------------|
  • Next, go to the Subnet Associations tab and associate the subnet you just created.
  • Finally, go back to your Lambda function and change the subnet(s) to only the subnet you just created. It should now have internet access. If you need more availability you can create additional subnets with different availability zones and repeat the same process.

Just to reiterate, NAT Gateway does NOT have a free tier so keep that in mind. Here's the pricing info https://aws.amazon.com/vpc/pricing/