A signed HTTP request for AWS resources

1 minute read

Recently, I was working with AWS elasticsearch service and I had AWS Lambda function which does some busiess logic interacting with elasticsearch service. While making an http call to elasticsearch service from AWS Lambda function, we need to sign the the http request with Signature Version 4. To get this signing process easy, I decided to use aws-java-sdk-core library which uses Apache HttpComponents for http communication. Here is sample code to make a [signed] http request to AWS elasticsearch service:

    // Create the request
    Request<Void> request = new DefaultRequest<Void>("es");
    request.setHttpMethod(HttpMethodName.GET);
    request.setEndpoint(URI.create("http://..."));

    // Sign it
    AWS4Signer signer = new AWS4Signer();
    signer.setRegionName("...");
    signer.setServiceName(request.getServiceName());
    signer.sign(request, new AwsCredentialsFromSystem());

    // Execute and get the response
    Response<String> rsp = new AmazonHttpClient(new ClientConfiguration())
        .requestExecutionBuilder()
        .executionContext(new ExecutionContext(true))
        .request(request)
        .errorResponseHandler(new MyErrorHandler())
        .execute(new MyResponseHandler<String>());

So, while writing this code, I was also thinking inline with this article about the above code. But, rather than using the tunnel decorators, I decided to use jcabi-http a fluent http api for my purpose. Sample code with jcabi will be as follows:

    String name = new JdkRequest("http://...")
      .fetch()
      .as(JsonResponse.class)
      .json()
      .readJsonObject().getString("name");

That being said, I need to provide a way to sign the the http request of jcabi-http api. Thus I decided to implement the Wire interface to sign the request. This wire implementation will take the necessary signing input parameters for signing process. The future state of api can be depicted as below:

    String name = new JdkRequest("http://...")
      .through(AwsSigner.class, new AwsSignParams("id", "key", "region", "service"));
      .fetch()
      .as(JsonResponse.class)
      .json()
      .readJsonObject().getString("name");

The only thing I saw missing here is lots of old dependencies and a lot more dependencies. The lot more dependencies means increase in your footprint of deployment package of AWS Lambda function. Thus I decided to create my own aws-http library to sign the http request for AWS services. I am not saying that this is perfect and everyone should use it, but rather I want to learn new things! The code snippet with aws-http api will be:

    MyClass myClassObject = new JdkRequest("https://www.somehost.com")
          .method(RequestMethod.GET)
          .path("/mypath")
          .queryParams("message", "hello*world")
          .header("Accept", "application/json")
          .header("Content-Type", "application/json")
          .body("{}")
          .sign(AwsSignParams("myAccessKey", "MySecretId", "es"))
          .execute()
          .getAs(MyClass.class);

Credits

I would like to extend the credits to


Tagged with : aws aws-sign-v4 http http-client aws-http

Updated: