この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
CX事業本部@大阪の岩田です。
現在関わっている案件でIAM認証を付けたAPI GWのエンドポイントにリクエストを発行する必要が出てきました。Node.jsに関しては先日佐藤が調べた通りなのですが、私の案件では諸々の理由からAWS SDK for Javaのv1を使う必要があったのでやり方を調べてみました。
Node.jsの場合はこちら↓
要件的には
- 現在AWS SDK for Javaのv1を使ったJavaのプログラムが稼働しており、AWS SDK for Javaのv2には上げたくない
- API GWのSDK生成機能は使いたくない
- SIGV4の署名ロジックを独自実装するのではなく、実績のあるライブラリに乗っかりたい → 可能ならAWS SDK for Java v1でやりたい。
といった要件になります。わざわざSIGv4の署名を作らなくてもAPI GatewayのAPIキーで認証してしまえば楽なのですが、APIキーを認証目的で利用することは非推奨なので、頑張ってSIGv4の署名を作成します。
認証および API の認証の唯一の手段として API キーに依存しないようにしてください。まず、使用量プランに複数の API がある場合、その使用量プランの 1 つの API に対して有効な API キーを持つユーザーは、その使用量プランのすべての API にアクセスできます。代わりに、IAM ロール、Lambda オーソライザー、または Amazon Cognito ユーザープールを使用します。
API キーを使用する使用量プランの作成と使用
環境
- Java SE 1.8.0_171
- aws-java-sdk-core-1.11.727
やり方
com.amazonaws.auth.AWS4Signer
クラスのsign
メソッドを使うことでSIGv4の署名を作成できます。sign
メソッドの引数にはインターフェースSignableRequest
を渡してやる必要があります。汎用的な具象クラスとしてcom.amazonaws.DefaultRequest
が使えるので、こいつを使いましょう。
重要なのは以下のポイントです。
DefaultRequest
のコンストラクタにexecute-api
を渡してやるDefaultRequest
のsetEndpoint
でAPI Gatewayのエンドポイントを設定するDefaultRequest
のsetResourcePath
で実行したいAPIのリソースパスを設定するDefaultRequest
のsetHttpMethod
で実行したいAPIのHTTPメソッドを指定する
Main.java
package com.classmethod.awssdkexample;
import com.amazonaws.auth.AWS4Signer;
import com.amazonaws.auth.BasicSessionCredentials;
import com.amazonaws.AmazonWebServiceResponse;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.DefaultRequest;
import com.amazonaws.http.AmazonHttpClient;
import com.amazonaws.http.HttpMethodName;
import com.amazonaws.Response;
import java.util.Date;
import java.net.URI;
public class Main {
public static void main(String[] args) {
AWS4Signer signer = new AWS4Signer();
String awsAccessKey = "<アクセスキー>";
String awsSecretKey = "<シークレットキー>";
String sessionToken = "<セッショントークン>";
BasicSessionCredentials cred = new BasicSessionCredentials(
awsAccessKey, awsSecretKey, sessionToken
);
DefaultRequest req = new DefaultRequest("execute-api");
req.setEndpoint(URI.create("https://<API GWのエンドポイント>.execute-api.ap-northeast-1.amazonaws.com"));
req.setResourcePath("<実行したいAPIのパス 例:/pets>");
req.setHttpMethod(HttpMethodName.fromValue("<実行したいAPIのHTTPメソッド 例:GET>"));
signer.setOverrideDate(new Date());
signer.setRegionName("ap-northeast-1");
signer.setServiceName("execute-api");
signer.sign(req, cred);
ClientConfiguration clientConfiguration = new ClientConfiguration();
AmazonHttpClient client = new AmazonHttpClient(clientConfiguration);
Response<AmazonWebServiceResponse<String>> res = client.requestExecutionBuilder()
.request(req)
.execute(new StringResponseHandler());
System.out.println(res.getAwsResponse().getResult());
}
}
今回はAPIのレスポンスをそのまま標準出力に吐き出したいだけだったので、Stack Overflowの記事を参考にHttpResponseHandler
インターフェースを実装したクラスを作成してAPI呼び出し時のハンドラーに指定しています。今回の検証はSIGv4の署名を作成してIAM認証を通すまでがゴールなので、本来考慮すべき諸々の処理を省略しています。もし実際に本番利用される場合は適宜処理を修正/追加頂くようお願いします。
StringResponseHandler.java
package com.classmethod.awssdkexample;
import com.amazonaws.AmazonWebServiceResponse;
import com.amazonaws.http.HttpResponseHandler;
import com.amazonaws.util.IOUtils;
import java.io.IOException;
public class StringResponseHandler implements HttpResponseHandler<AmazonWebServiceResponse<String>> {
@Override
public AmazonWebServiceResponse<String> handle(com.amazonaws.http.HttpResponse response) throws IOException {
AmazonWebServiceResponse<String> awsResponse = new AmazonWebServiceResponse<>();
awsResponse.setResult(IOUtils.toString(response.getContent()));
return awsResponse;
}
@Override
public boolean needsConnectionLeftOpen() {
return false;
}
}
まとめ
Javaの経験が無いので大変でしたが、ドキュメントを見つつなんとか実装できて良かったです。