開発環境のHasura ConsoleでDataタブを開くと 403 Forbidden エラーが発生しました。
原因と対応をメモしておきます。
エラーレスポンスは以下です。JSONではなくHTMLで返却されています。
HTTP/2 403
server: awselb/2.0date: Wed, 18 Jan 2023 06:43:38 GMT
content-type: text/html
content-length: 520
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
</body>
</html>
<!-- a padding to disable MSIE and Chrome friendly error page >
<!-- a padding to disable MSIE and Chrome friendly error page >
<!-- a padding to disable MSIE and Chrome friendly error page >
<!-- a padding to disable MSIE and Chrome friendly error page >
<!-- a padding to disable MSIE and Chrome friendly error page >
<!-- a padding to disable MSIE and Chrome friendly error page >
原因
AWS WAF の AWSManagedRulesCommonRuleSet#SizeRestrictions_BODY の制限にかかっていたことが原因でした。
* コアルールセット \(CRS\) マネージドルールグループ
具体的には、Hasura Console の Dataタブを開いた際に実行しているAPIの /v2/query のボディサイズが約13KBだったために、SizeRestrictions_BODY の制限である 8KB を超過してエラーになっていました。
リクエストボディの内容は以下です。実際にはargs内のsqlの値が長めのSQLクエリになっています。
{
"type": "bulk",
"source": "app",
"args": [
{
"type": "run_sql",
"args": {
"source": "app",
"sql": "SELECT...",
"cascade": false,
"read_only": true
}
},
{
"type": "run_sql",
"args": {
"source": "app",
"sql": "SELECT...",
"cascade": false,
"read_only": true
}
},
{
"type": "run_sql",
"args": {
"source": "app",
"sql": "SELECT...",
"cascade": false,
"read_only": true
}
},
{
"type": "run_sql",
"args": {
"source": "app",
"sql": "SELECT...",
"cascade": false,
"read_only": true
}
},
{
"type": "run_sql",
"args": {
"source": "app",
"sql": "SELECT...",
"cascade": false,
"read_only": true
}
}
]
}
対応
次の対応方法を考えました。
1. 特定のIPアドレスをWAFのホワイトリストに追加
2. AWSManagedRulesCommonRuleSet#SizeRestrictions_BODYを無効化
今回はそもそもHasura ConsoleにIPアドレス制限をかけているため、(1)で対応します。
以下はAWS CDKでWAFにIPアドレス許可ルールを追加するサンプルです。
const allowIpSets = new CfnIPSet(this.scope, "XXX", {
name: "XXX",
ipAddressVersion: "IPV4",
scope: "REGIONAL",
addresses: ["1.2.3.4/32"],
});
let priority = 0;
new CfnWebACL(this.scope, "XXX", {
defaultAction: {
allow: {},
},
scope: "REGIONAL",
name: "XXX",
visibilityConfig: {
sampledRequestsEnabled: false,
cloudWatchMetricsEnabled: true,
metricName: `XXX`,
},
rules: [
{
priority: priority++,
name: `XXX`,
action: { allow: {} },
visibilityConfig: {
sampledRequestsEnabled: false,
cloudWatchMetricsEnabled: true,
metricName: "XXX",
},
statement: {
ipSetReferenceStatement: {
arn: allowIpSets.attrArn,
},
},
},
// ...
さいごに
最初はHasuraのDBユーザーの権限を疑いましたが、そもそもレスポンスがHTMLで返却されている時点で、Hasura側の問題ではないと気がつくべきでした。事実ベースで仮説を立てるのが大事ですね。
株式会社Grandreamでは、フルリモートであなたのスキルを活かし、活躍できるエンジニアを募集しております。
詳しくは採用ページをご確認いただき、お気軽にお問い合わせください。