はじめに
AWSでサーバーレスwebアプリケーションを作りました.
アーキテクチャはこんな感じ
認可処理は,cookieに設定したJWTにより検証を行っています.
表題の件
図にあるように,API GatewayへのアクセスはリソースポリシーによるIP制限をかけていました.
こんな感じで
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:<region>:<account-id>:<api-id>/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"xxx.xx.xx.xxx",
"xxx.xx.xx.xxx",
"xxx.xx.xx.xxx"
]
}
}
}
]
}
いわゆるホワイトリストでIP制限をかけています. 特定のIPリソースからのアクセスのみ許可するという風に.
そして今回設定したAPI Gateway のリソースは大きく分けて以下の2種類です.
ここで,上記1. のケースではリソースポリシーによる意図したIP制限が行われましたが,2. のケースでは意図した挙動をしてくれませんでした.
明示的/暗黙的な許可/拒否の話
Lambdaオーソライザーを設定した場合にリソースポリシーが適用されない原因は,ポリシーの評価方法が異なるためです.
デフォルトではAPI GatewayへのアクセスポリシーはDenyから始まります.先に示したリソースポリシーでは,特定のIPリソースからのアクセスだと判断されればAllowとするというものなので,結果的にポリシーはAllowとなります.(明示的な許可)
一方,Lambdaオーソライザーを設定した場合は,リソースポリシーとLambdaオーソライザーから返却されるポリシーを合わせて評価されます.
それぞれのポリシーの評価結果による最終的な動作は,以下のようになります.
Lambdaオーソライザーポリシー | API Gateway リソースポリシー | 結果として生じる動作 |
---|---|---|
許可 | 許可 | 許可 |
許可 | 許可も拒否もしない | 許可 |
許可 | 拒否 | 明示的な拒否 |
許可も拒否もしない | 許可 | 許可 |
許可も拒否もしない | 許可も拒否もしない | 暗黙的な拒否 |
許可も拒否もしない | 拒否 | 明示的な拒否 |
拒否 | 許可 | 明示的な拒否 |
拒否 | 許可も拒否もしない | 明示的な拒否 |
拒否 | 拒否 | 明示的な拒否 |
ホワイトリスト以外のIPリソースからのアクセスの場合,(先に記したリソースポリシーでは,特定のIPリソースからのアクセスには明示的な許可がされていますが,)明示的な拒否が設定されていないため,上記の表での許可も拒否もしないに当たります.
つまり,正しいJWTを設定したアクセスが行われた場合,Lambdaオーソライザーポリシーは許可なので,アクセス元のIPリソースが何であっても,結果としてAllowとなっていた,ということになります.
事象のまとめ
- リソースポリシー単体とLambdaオーソライザーを組み合わせた場合のポリシー評価方法は異なる.
- 明示的な拒否がされていない場合,いずれかのポリシーが許可の場合,結果的にAllowとなる.
- 今回のケースでは,明示的な拒否がされていなかった.
解決策
リソースポリシーに明示的な拒否を加えることで,意図した動作をさせることが可能です.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:<region>:<account-id>:<api-id>/*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": [
"xxx.xx.xx.xxx",
"xxx.xx.xx.xxx",
"xxx.xx.xx.xxx"
]
}
}
},
{
"Effect": "Allow",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": [
"arn:aws:execute-api:<region>:<account-id>:<api-id>/*/",
"arn:aws:execute-api:<region>:<account-id>:<api-id>/*/login",
"arn:aws:execute-api:<region>:<account-id>:<api-id>/*/initiate-auth",
"arn:aws:execute-api:<region>:<account-id>:<api-id>/*/confirm-forgot-password"
],
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"xxx.xx.xx.xxx",
"xxx.xx.xx.xxx",
"xxx.xx.xx.xxx"
]
}
}
}
]
}
- 明示的な拒否では,特定のIPリソースからのアクセスは拒否
- Lambdaオーソライザーを設定しないAPIリソースに対しては,明示的な許可を設定
これで,特定のIPリソースからのアクセスのみに制限することができました.