HTTP API ではリソースポリシーが使えない
REST API で IP アドレス制限するには、通常、リソースポリシーを使います。
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/apigateway-resource-policies-examples.html#apigateway-resource-policies-source-ip-address-example
でも、後発の HTTP API では、リソースポリシーが未実装です。
AWS WAF も未対応なので、そっちで IP アドレス制限することもできません。
Lambda Authorizer でできる
昔、REST API にリソースポリシーがなかった頃、IP アドレスで制限するには、Lambda Authorizer を利用していました。
その方法を試してみたところ、HTTP API でも利用できました。
- HTTP API の Lambda Authorizer のレスポンスモードを
IAM ポリシーにする
- Lambda Authorizer が返す IAM ポリシーの Condition に
IpAddress
とaws:SourceIp
を追加する
exports.handler = async function (event, context) {
const response = {
principalId: "hoge",
policyDocument: {
Version: "2012-10-17",
Statement: [
{
Effect: "Allow",
Action: "execute-api:Invoke",
Resource: event.routeArn,
Condition: {
IpAddress: {
"aws:SourceIp": ["192.168.0.1/32"]
}
}
}
]
}
}
return response;
};
この例では、192.168.0.1
からのリクエストのみ許可されます。
制限したい IP アドレスが 1 つだけなら、Lambda Authorizer のロジックで判定してもあまり変わらないですが、IP アドレスが複数だったり、CIDR のホスト部が 32
より小さい場合、ロジックがややこしくなります。
その点、この方法だと AWS 側が判定してくれるので楽です。
他の条件も試してみる
これができるなら、他の 条件キー も使えるのではと、やってみました。
aws:CurrentTime ✅
exports.handler = async function (event, context) {
const response = {
principalId: "hoge",
policyDocument: {
Version: "2012-10-17",
Statement: [
{
Effect: "Allow",
Action: "execute-api:Invoke",
Resource: event.routeArn,
Condition: {
DateGreaterThan: {
"aws:CurrentTime": "2023-12-05T18:10:00+09:00"
}
}
}
]
}
}
return response;
};
2023/12/05 18:10
より前では Forbidden でしたが、その日時を過ぎるとアクセスできました。
2023/12/25T00:00:00+09:00
に設定して、日本時間でクリスマスになったら公開するとか使い所がありそう。
逆に DateLessThan
を使うと、その日時まで公開することもできますね。
期間限定のサイトとかに使えそう。
aws:Referer ❌
exports.handler = async function (event, context) {
const response = {
principalId: "hoge",
policyDocument: {
Version: "2012-10-17",
Statement: [
{
Effect: "Allow",
Action: "execute-api:Invoke",
Resource: event.routeArn,
Condition: {
StringLike: {
"aws:Referer": ["http://example.com/*"]
}
}
}
]
}
}
return response;
};
エラーは起きないですが、無視されるようで、使えず。
一方で、Rest API のリソースポリシーでは使えました。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": [
"execute-api:/*"
],
"Condition": {
"StringLike": {
"aws:Referer": ["http://example.com/*"]
}
}
}
]
}
aws:UserAgent ❌
exports.handler = async function (event, context) {
const response = {
principalId: "hoge",
policyDocument: {
Version: "2012-10-17",
Statement: [
{
Effect: "Allow",
Action: "execute-api:Invoke",
Resource: event.routeArn,
Condition: {
StringLike: {
"aws:UserAgent": ["Mozilla/*"]
}
}
}
]
}
}
return response;
};
こっちもダメ。
でも Rest API のリソースポリシーは OK。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": [
"execute-api:/*"
],
"Condition": {
"StringLike": {
"aws:UserAgent": ["Mozilla/*"]
}
}
}
]
}
まとめ
AWS のグローバル条件キーはたくさんありますが、HTTP API では IP アドレス制限と期間限定以外に使えそうなものはあまりなさそうでした。残念。
結局何が言いたいかというと、HTTP API でもリソースポリシーと WAF を早く実装してください 🙏 > AWS