AWS - Lambda function URLs を IAM 署名付きでリクエストしてみる
少し前に、Lambdaで直接URL発行ができるようになったやつ。
使ってみた投稿は多々あるが、どれもIAM署名付きでリクエストしている事例がない。
あったとしても、awscurlとか使ってるので、そのままではアプリケーションに組み込めない。
なので、どうやってIAM署名付きでリクエストできるのか気になったので、試してみる。
AWS_IAM auth type
Auth typeは、AWS_IAMとNONEの2種類ある。
名前の通り、AWS_IAMを指定すると、IAMで認証できるようになる。
権限としては、Function
に対するlambda:InvokeFunctionUrl
の呼び出し権限があれば良いとのこと。
Signature Version 4
IAM 署名付きでリクエストするには、Signature Version 4
という方法で現在は署名を付与する必要があるらしい。
Lambdaのドキュメントを見た限りでは、AWS SDKを使っている場合は内部でいい感じにやってくれているが、Function URLsの場合は適当にツール使って頑張ってくれ、とのこと。
@aws-sdk/signature-v4
流石に自分で処理を組み立てるのは面倒くさいので、AWS SDKで署名を付与する方向で進めてみる。
JS用のSDKに@aws-sdk/signature-v4
というパッケージがある。
で、テストコードを見ると、HTTPリクエスト内容に対して、署名を付与してそう。
それらを参考に、署名付きでHTTPリクエストするコードを書いてみると、こんな感じ。
const { SignatureV4 } = require('@aws-sdk/signature-v4');
const { defaultProvider } = require('@aws-sdk/credential-provider-node');
const { Sha256 } = require('@aws-crypto/sha256-js');
const { HttpRequest } = require('@aws-sdk/protocol-http');
(async () => {
const signer = new SignatureV4({
region: 'ap-northeast-1',
service: 'lambda',
sha256: Sha256,
credentials: defaultProvider(),
});
const req = await signer.sign(
new HttpRequest({
method: 'POST',
protocol: 'https:',
path: '/',
hostname: 'ny4p5y5glmfuyzmv6m2xz6rw640khtse.lambda-url.ap-northeast-1.on.aws',
headers: {
host: 'ny4p5y5glmfuyzmv6m2xz6rw640khtse.lambda-url.ap-northeast-1.on.aws',
},
body: JSON.stringify({ hello: 'world' }),
})
);
console.log(req);
const res = await fetch(`${req.protocol}${req.hostname}${req.path}`, {
method: req.method,
body: req.body,
headers: req.headers,
});
console.log(await res.json());
})();
これで、リクエストしてみると、レスポンスが返ってきた。
$ node --no-warnings request.js
HttpRequest {
method: 'POST',
hostname: 'ny4p5y5glmfuyzmv6m2xz6rw640khtse.lambda-url.ap-northeast-1.on.aws',
port: undefined,
query: {},
headers: {
host: 'ny4p5y5glmfuyzmv6m2xz6rw640khtse.lambda-url.ap-northeast-1.on.aws',
'x-amz-date': '20220509T145201Z',
'x-amz-content-sha256': 'xxxxx',
authorization: 'AWS4-HMAC-SHA256 Credential=xxxxx/20220509/ap-northeast-1/lambda/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=xxxxx'
},
body: '{"hello":"world"}',
protocol: 'https:',
path: '/'
}
"Hello from Lambda!"
そして、ヘッダーを外してリクエストしてみると、意図したとおり認証が通らず、Forbidden
で返ってきた。
$ node --no-warnings request.js
...
{"Message":"Forbidden"}
これで、Lambda function URLs を IAM 署名付きでリクエストできたと思う。
まとめ
SDK使った署名付きリクエスト方法ぐらいは、公式ドキュメントに含めても良いような?
Discussion