Invoking AWS_IAM Auth Lambda Function URL with Java 11+ HttpClient 📎
If your Lambda Function URL uses the AWS_IAM
auth type:
import software.amazon.awscdk.services.lambda.FunctionUrlAuthType;
import software.amazon.awscdk.services.lambda.FunctionUrlOptions;
var functionUrl = function.addFunctionUrl(FunctionUrlOptions.builder()
.authType(FunctionUrlAuthType.AWS_IAM)
.build());
you must sign each HTTP request using AWS Signature Version 4 (SigV4).
The class Aws4Signer ships with the dependency:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>auth</artifactId>
<version>2.17.191</version>
</dependency>
...as well as the SDK:
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>aws-sdk-java</artifactId>
<version>2.17.191</version>
</dependency>
To sign a request:
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse.BodyHandlers;
import java.util.List;
import org.junit.jupiter.api.Test;
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.auth.signer.Aws4Signer;
import software.amazon.awssdk.auth.signer.params.Aws4SignerParams;
import software.amazon.awssdk.http.SdkHttpFullRequest;
import software.amazon.awssdk.http.SdkHttpMethod;
import software.amazon.awssdk.regions.Region;
public class JavaHTTP11ClientTest {
@Test
public void signedHttpGET() throws IOException, InterruptedException {
var uri = URI.create("https://mtpe2t7ucalsample62y0zkfwq.lambda-url.eu-central-1.on.aws/hello/");
var host = uri.getHost();
var path = uri.getPath();
...you have to create a SdkHttpFullRequest
first:
var fullRequest = SdkHttpFullRequest.builder()
.encodedPath(path)
.host(host)
.protocol("https")
.method(SdkHttpMethod.GET)
.build();
The request is passed to AWS Signature Version 4 (SigV4) utility, which performs the signing:
var signedRequest = Aws4Signer.create().sign(fullRequest,
Aws4SignerParams.builder()
.signingName("lambda")
.awsCredentials(DefaultCredentialsProvider.create()
.resolveCredentials())
.signingRegion(Region.EU_CENTRAL_1)
.build());
The signature is is passed as Authorization
and X-Amz-Date
headers to the Java 11 HttpClient:
//Java 11+ HttpClient
var client = HttpClient.newHttpClient();
var builder = HttpRequest.newBuilder(uri);
signedRequest.headers().forEach((name, list) -> addHeader(builder, name, list));
var request = builder.GET().build();
var response = client.send(request, BodyHandlers.ofString());
var status = response.statusCode();
var body = response.body();
//...
}
static void addHeader(HttpRequest.Builder requestBuilder,String name, List<String> values){
if(name.equalsIgnoreCase("host")){
return;
}
values.forEach(value -> requestBuilder.header(name, value));
}
}
The function URL Lambda from this example is based on the MicroProfile with Quarkus as AWS Lambda Function deployed with Cloud Development Kit (CDK) v2 for Java template.